@@ -6061,19 +6061,38 @@ omp_check_private (struct gimplify_omp_c
{
ctx = ctx->outer_context;
if (ctx == NULL)
- return !(is_global_var (decl)
- /* References might be private, but might be shared too,
- when checking for copyprivate, assume they might be
- private, otherwise assume they might be shared. */
- || (!copyprivate
- && lang_hooks.decls.omp_privatize_by_reference (decl)));
+ {
+ if (is_global_var (decl))
+ return false;
+
+ /* References might be private, but might be shared too,
+ when checking for copyprivate, assume they might be
+ private, otherwise assume they might be shared. */
+ if (copyprivate)
+ return true;
+
+ if (lang_hooks.decls.omp_privatize_by_reference (decl))
+ return false;
+
+ /* Treat C++ privatized non-static data members outside
+ of the privatization the same. */
+ if (omp_member_access_dummy_var (decl))
+ return false;
+
+ return true;
+ }
if ((ctx->region_type & (ORT_TARGET | ORT_TARGET_DATA)) != 0)
continue;
n = splay_tree_lookup (ctx->variables, (splay_tree_key) decl);
if (n != NULL)
- return (n->value & GOVD_SHARED) == 0;
+ {
+ if ((n->value & GOVD_LOCAL) != 0
+ && omp_member_access_dummy_var (decl))
+ return false;
+ return (n->value & GOVD_SHARED) == 0;
+ }
}
while (ctx->region_type == ORT_WORKSHARE
|| ctx->region_type == ORT_SIMD);
@@ -6357,6 +6376,17 @@ gimplify_scan_omp_clauses (tree *list_p,
remove = true;
break;
}
+ if (DECL_NAME (decl) == NULL_TREE && (flags & GOVD_SHARED) == 0)
+ {
+ tree t = omp_member_access_dummy_var (decl);
+ if (t)
+ {
+ tree v = DECL_VALUE_EXPR (decl);
+ DECL_NAME (decl) = DECL_NAME (TREE_OPERAND (v, 1));
+ if (outer_ctx)
+ omp_notice_variable (outer_ctx, t, true);
+ }
+ }
omp_add_variable (ctx, decl, flags);
if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION
&& OMP_CLAUSE_REDUCTION_PLACEHOLDER (c))
@@ -337,6 +337,73 @@ oacc_max_threads (omp_context *ctx)
return nthreads;
}
+/* If DECL is the artificial dummy VAR_DECL created for non-static
+ data member privatization, return the underlying "this" parameter,
+ otherwise return NULL. */
+
+tree
+omp_member_access_dummy_var (tree decl)
+{
+ if (!VAR_P (decl)
+ || !DECL_ARTIFICIAL (decl)
+ || !DECL_IGNORED_P (decl)
+ || !DECL_HAS_VALUE_EXPR_P (decl)
+ || !lang_hooks.decls.omp_disregard_value_expr (decl, false))
+ return NULL_TREE;
+
+ tree v = DECL_VALUE_EXPR (decl);
+ if (TREE_CODE (v) != COMPONENT_REF)
+ return NULL_TREE;
+
+ while (1)
+ switch (TREE_CODE (v))
+ {
+ case COMPONENT_REF:
+ case MEM_REF:
+ case INDIRECT_REF:
+ CASE_CONVERT:
+ case POINTER_PLUS_EXPR:
+ v = TREE_OPERAND (v, 0);
+ continue;
+ case PARM_DECL:
+ if (DECL_CONTEXT (v) == current_function_decl
+ && DECL_ARTIFICIAL (v)
+ && TREE_CODE (TREE_TYPE (v)) == POINTER_TYPE)
+ return v;
+ return NULL_TREE;
+ default:
+ return NULL_TREE;
+ }
+}
+
+/* Helper for unshare_and_remap, called through walk_tree. */
+
+static tree
+unshare_and_remap_1 (tree *tp, int *walk_subtrees, void *data)
+{
+ tree *pair = (tree *) data;
+ if (*tp == pair[0])
+ {
+ *tp = unshare_expr (pair[1]);
+ *walk_subtrees = 0;
+ }
+ else if (IS_TYPE_OR_DECL_P (*tp))
+ *walk_subtrees = 0;
+ return NULL_TREE;
+}
+
+/* Return unshare_expr (X) with all occurrences of FROM
+ replaced with TO. */
+
+static tree
+unshare_and_remap (tree x, tree from, tree to)
+{
+ tree pair[2] = { from, to };
+ x = unshare_expr (x);
+ walk_tree (&x, unshare_and_remap_1, pair, NULL);
+ return x;
+}
+
/* Holds offload tables with decls. */
vec<tree, va_gc> *offload_funcs, *offload_vars;
@@ -1103,7 +1170,7 @@ use_pointer_for_field (tree decl, omp_co
tree outer;
maybe_mark_addressable_and_ret:
outer = maybe_lookup_decl_in_outer_ctx (decl, shared_ctx);
- if (is_gimple_reg (outer))
+ if (is_gimple_reg (outer) && !omp_member_access_dummy_var (outer))
{
/* Taking address of OUTER in lower_send_shared_vars
might need regimplification of everything that uses the
@@ -1241,7 +1308,8 @@ build_outer_var_ref (tree var, omp_conte
x = build_simple_mem_ref (ctx->outer->receiver_decl);
x = omp_build_component_ref (x, field);
- x = build_simple_mem_ref (x);
+ if (use_pointer_for_field (var, ctx->outer))
+ x = build_simple_mem_ref (x);
}
}
else if (ctx->outer)
@@ -1250,9 +1318,25 @@ build_outer_var_ref (tree var, omp_conte
/* This can happen with orphaned constructs. If var is reference, it is
possible it is shared and as such valid. */
x = var;
+ else if (omp_member_access_dummy_var (var))
+ x = var;
else
gcc_unreachable ();
+ if (x == var)
+ {
+ tree t = omp_member_access_dummy_var (var);
+ if (t)
+ {
+ x = DECL_VALUE_EXPR (var);
+ tree o = maybe_lookup_decl_in_outer_ctx (t, ctx);
+ if (o != t)
+ x = unshare_and_remap (x, t, o);
+ else
+ x = unshare_expr (x);
+ }
+ }
+
if (is_reference (var))
x = build_simple_mem_ref (x);
@@ -1758,10 +1842,7 @@ scan_sharing_clauses (tree clauses, omp_
break;
by_ref = use_pointer_for_field (decl, ctx);
if (OMP_CLAUSE_SHARED_FIRSTPRIVATE (c))
- {
- gcc_assert (by_ref);
- break;
- }
+ break;
if (! TREE_READONLY (decl)
|| TREE_ADDRESSABLE (decl)
|| by_ref
@@ -2046,7 +2127,8 @@ scan_sharing_clauses (tree clauses, omp_
break;
if (OMP_CLAUSE_SHARED_FIRSTPRIVATE (c))
{
- install_var_field (decl, true, 11, ctx);
+ bool by_ref = use_pointer_for_field (decl, ctx);
+ install_var_field (decl, by_ref, 11, ctx);
break;
}
fixup_remapped_decl (decl, ctx, false);
@@ -4843,7 +4925,7 @@ static void
lower_send_clauses (tree clauses, gimple_seq *ilist, gimple_seq *olist,
omp_context *ctx)
{
- tree c;
+ tree c, t;
int ignored_looptemp = 0;
/* For taskloop, ignore first two _looptemp_ clauses, those are initialized
@@ -4890,6 +4972,17 @@ lower_send_clauses (tree clauses, gimple
&& is_global_var (var))
continue;
+ t = omp_member_access_dummy_var (var);
+ if (t)
+ {
+ var = DECL_VALUE_EXPR (var);
+ tree o = maybe_lookup_decl_in_outer_ctx (t, ctx);
+ if (o != t)
+ var = unshare_and_remap (var, t, o);
+ else
+ var = unshare_expr (var);
+ }
+
if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_SHARED)
{
/* Handle taskloop firstprivate/lastprivate, where the
@@ -4900,9 +4993,9 @@ lower_send_clauses (tree clauses, gimple
splay_tree_lookup (ctx->sfield_map
? ctx->sfield_map : ctx->field_map,
(splay_tree_key) &DECL_UID (val))->value;
- gcc_assert (use_pointer_for_field (val, ctx));
x = omp_build_component_ref (ctx->sender_decl, f);
- var = build_fold_addr_expr (var);
+ if (use_pointer_for_field (val, ctx))
+ var = build_fold_addr_expr (var);
gimplify_assign (x, var, ilist);
DECL_ABSTRACT_ORIGIN (f) = NULL;
continue;
@@ -4969,7 +5062,7 @@ lower_send_clauses (tree clauses, gimple
static void
lower_send_shared_vars (gimple_seq *ilist, gimple_seq *olist, omp_context *ctx)
{
- tree var, ovar, nvar, f, x, record_type;
+ tree var, ovar, nvar, t, f, x, record_type;
if (ctx->record_type == NULL)
return;
@@ -4990,6 +5083,17 @@ lower_send_shared_vars (gimple_seq *ilis
mapping for OVAR. */
var = lookup_decl_in_outer_ctx (ovar, ctx);
+ t = omp_member_access_dummy_var (var);
+ if (t)
+ {
+ var = DECL_VALUE_EXPR (var);
+ tree o = maybe_lookup_decl_in_outer_ctx (t, ctx);
+ if (o != t)
+ var = unshare_and_remap (var, t, o);
+ else
+ var = unshare_expr (var);
+ }
+
if (use_pointer_for_field (ovar, ctx))
{
x = build_sender_ref (ovar, ctx);
@@ -11615,22 +11719,19 @@ create_task_copyfn (gomp_task *task_stmt
for (c = gimple_omp_task_clauses (task_stmt); c; c = OMP_CLAUSE_CHAIN (c))
switch (OMP_CLAUSE_CODE (c))
{
+ splay_tree_key key;
case OMP_CLAUSE_SHARED:
decl = OMP_CLAUSE_DECL (c);
- n = splay_tree_lookup (ctx->field_map, (splay_tree_key) decl);
+ key = (splay_tree_key) decl;
+ if (OMP_CLAUSE_SHARED_FIRSTPRIVATE (c))
+ key = (splay_tree_key) &DECL_UID (decl);
+ n = splay_tree_lookup (ctx->field_map, key);
if (n == NULL)
break;
- if (OMP_CLAUSE_SHARED_FIRSTPRIVATE (c))
- {
- decl = (tree) n->value;
- n = splay_tree_lookup (ctx->field_map, (splay_tree_key) decl);
- if (n == NULL)
- break;
- }
f = (tree) n->value;
if (tcctx.cb.decl_map)
f = *tcctx.cb.decl_map->get (f);
- n = splay_tree_lookup (ctx->sfield_map, (splay_tree_key) decl);
+ n = splay_tree_lookup (ctx->sfield_map, key);
sf = (tree) n->value;
if (tcctx.cb.decl_map)
sf = *tcctx.cb.decl_map->get (sf);
@@ -12424,10 +12525,73 @@ lower_omp_regimplify_p (tree *tp, int *w
if (data == NULL && TREE_CODE (t) == ADDR_EXPR)
recompute_tree_invariant_for_addr_expr (t);
- *walk_subtrees = !TYPE_P (t) && !DECL_P (t);
+ *walk_subtrees = !IS_TYPE_OR_DECL_P (t);
+ return NULL_TREE;
+}
+
+/* Data to be communicated between lower_omp_regimplify_operands and
+ lower_omp_regimplify_operands_p. */
+
+struct lower_omp_regimplify_operands_data
+{
+ omp_context *ctx;
+ vec<tree> *decls;
+};
+
+/* Helper function for lower_omp_regimplify_operands. Find
+ omp_member_access_dummy_var vars and adjust temporarily their
+ DECL_VALUE_EXPRs if needed. */
+
+static tree
+lower_omp_regimplify_operands_p (tree *tp, int *walk_subtrees,
+ void *data)
+{
+ tree t = omp_member_access_dummy_var (*tp);
+ if (t)
+ {
+ struct walk_stmt_info *wi = (struct walk_stmt_info *) data;
+ lower_omp_regimplify_operands_data *ldata
+ = (lower_omp_regimplify_operands_data *) wi->info;
+ tree o = maybe_lookup_decl (t, ldata->ctx);
+ if (o != t)
+ {
+ ldata->decls->safe_push (DECL_VALUE_EXPR (*tp));
+ ldata->decls->safe_push (*tp);
+ tree v = unshare_and_remap (DECL_VALUE_EXPR (*tp), t, o);
+ SET_DECL_VALUE_EXPR (*tp, v);
+ }
+ }
+ *walk_subtrees = !IS_TYPE_OR_DECL_P (*tp);
return NULL_TREE;
}
+/* Wrapper around gimple_regimplify_operands that adjusts DECL_VALUE_EXPRs
+ of omp_member_access_dummy_var vars during regimplification. */
+
+static void
+lower_omp_regimplify_operands (omp_context *ctx, gimple stmt,
+ gimple_stmt_iterator *gsi_p)
+{
+ auto_vec<tree, 10> decls;
+ if (ctx)
+ {
+ struct walk_stmt_info wi;
+ memset (&wi, '\0', sizeof (wi));
+ struct lower_omp_regimplify_operands_data data;
+ data.ctx = ctx;
+ data.decls = &decls;
+ wi.info = &data;
+ walk_gimple_op (stmt, lower_omp_regimplify_operands_p, &wi);
+ }
+ gimple_regimplify_operands (stmt, gsi_p);
+ while (!decls.is_empty ())
+ {
+ tree t = decls.pop ();
+ tree v = decls.pop ();
+ SET_DECL_VALUE_EXPR (t, v);
+ }
+}
+
static void
lower_omp_1 (gimple_stmt_iterator *gsi_p, omp_context *ctx)
{
@@ -12462,7 +12626,7 @@ lower_omp_1 (gimple_stmt_iterator *gsi_p
|| walk_tree (gimple_cond_rhs_ptr (cond_stmt),
lower_omp_regimplify_p,
ctx ? NULL : &wi, NULL)))
- gimple_regimplify_operands (cond_stmt, gsi_p);
+ lower_omp_regimplify_operands (ctx, cond_stmt, gsi_p);
}
break;
case GIMPLE_CATCH:
@@ -12535,7 +12699,7 @@ lower_omp_1 (gimple_stmt_iterator *gsi_p
&& walk_tree (gimple_omp_atomic_load_rhs_ptr (
as_a <gomp_atomic_load *> (stmt)),
lower_omp_regimplify_p, ctx ? NULL : &wi, NULL))
- gimple_regimplify_operands (stmt, gsi_p);
+ lower_omp_regimplify_operands (ctx, stmt, gsi_p);
break;
case GIMPLE_OMP_TARGET:
ctx = maybe_lookup_ctx (stmt);
@@ -12616,7 +12780,7 @@ lower_omp_1 (gimple_stmt_iterator *gsi_p
gsi_replace (gsi_p, gimple_build_nop (), true);
break;
}
- gimple_regimplify_operands (stmt, gsi_p);
+ lower_omp_regimplify_operands (ctx, stmt, gsi_p);
}
break;
}
@@ -28,6 +28,7 @@ extern void free_omp_regions (void);
extern tree omp_reduction_init (tree, tree);
extern bool make_gimple_omp_edges (basic_block, struct omp_region **, int *);
extern void omp_finish_file (void);
+extern tree omp_member_access_dummy_var (tree);
extern GTY(()) vec<tree, va_gc> *offload_funcs;
extern GTY(()) vec<tree, va_gc> *offload_vars;
@@ -9483,6 +9483,8 @@ cp_parser_lambda_body (cp_parser* parser
/* Still increment function_depth so that we don't GC in the
middle of an expression. */
++function_depth;
+ vec<tree> omp_privatization_save;
+ save_omp_privatization_clauses (omp_privatization_save);
/* Clear this in case we're in the middle of a default argument. */
parser->local_variables_forbidden_p = false;
@@ -9584,6 +9586,7 @@ cp_parser_lambda_body (cp_parser* parser
expand_or_defer_fn (fn);
}
+ restore_omp_privatization_clauses (omp_privatization_save);
parser->local_variables_forbidden_p = local_variables_forbidden_p;
if (nested)
pop_function_context();
@@ -29520,7 +29523,7 @@ cp_parser_oacc_all_clauses (cp_parser *p
cp_parser_skip_to_pragma_eol (parser, pragma_tok);
if (finish_p)
- return finish_omp_clauses (clauses);
+ return finish_omp_clauses (clauses, false);
return clauses;
}
@@ -29805,7 +29808,7 @@ cp_parser_omp_all_clauses (cp_parser *pa
if (!(flag_cilkplus && pragma_tok == NULL))
cp_parser_skip_to_pragma_eol (parser, pragma_tok);
if (finish_p)
- return finish_omp_clauses (clauses);
+ return finish_omp_clauses (clauses, true);
return clauses;
}
@@ -30795,7 +30798,7 @@ cp_parser_omp_for_loop (cp_parser *parse
{
c = build_omp_clause (loc, OMP_CLAUSE_PRIVATE);
OMP_CLAUSE_DECL (c) = decl;
- c = finish_omp_clauses (c);
+ c = finish_omp_clauses (c, false);
if (c)
{
OMP_CLAUSE_CHAIN (c) = clauses;
@@ -30934,7 +30937,7 @@ cp_omp_split_clauses (location_t loc, en
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]);
+ cclauses[i] = finish_omp_clauses (cclauses[i], true);
}
/* OpenMP 4.0:
@@ -32027,7 +32030,7 @@ cp_parser_oacc_cache (cp_parser *parser,
tree stmt, clauses;
clauses = cp_parser_omp_var_list (parser, OMP_CLAUSE__CACHE_, NULL_TREE);
- clauses = finish_omp_clauses (clauses);
+ clauses = finish_omp_clauses (clauses, false);
cp_parser_require_pragma_eol (parser, cp_lexer_peek_token (parser->lexer));
@@ -33529,6 +33532,8 @@ cp_parser_pragma (cp_parser *parser, enu
{
cp_token *pragma_tok;
unsigned int id;
+ tree stmt;
+ bool ret;
pragma_tok = cp_lexer_consume_token (parser->lexer);
gcc_assert (pragma_tok->type == CPP_PRAGMA);
@@ -33670,14 +33675,22 @@ cp_parser_pragma (cp_parser *parser, enu
case PRAGMA_OMP_TEAMS:
if (context != pragma_stmt && context != pragma_compound)
goto bad_stmt;
+ stmt = push_omp_privatization_clauses ();
cp_parser_omp_construct (parser, pragma_tok);
+ pop_omp_privatization_clauses (stmt);
return true;
case PRAGMA_OMP_ORDERED:
- return cp_parser_omp_ordered (parser, pragma_tok, context);
+ stmt = push_omp_privatization_clauses ();
+ ret = cp_parser_omp_ordered (parser, pragma_tok, context);
+ pop_omp_privatization_clauses (stmt);
+ return ret;
case PRAGMA_OMP_TARGET:
- return cp_parser_omp_target (parser, pragma_tok, context);
+ stmt = push_omp_privatization_clauses ();
+ ret = cp_parser_omp_target (parser, pragma_tok, context);
+ pop_omp_privatization_clauses (stmt);
+ return ret;
case PRAGMA_OMP_END_DECLARE_TARGET:
cp_parser_omp_end_declare_target (parser, pragma_tok);
@@ -33718,7 +33731,9 @@ cp_parser_pragma (cp_parser *parser, enu
"%<#pragma simd%> must be inside a function");
break;
}
+ stmt = push_omp_privatization_clauses ();
cp_parser_cilk_simd (parser, pragma_tok);
+ pop_omp_privatization_clauses (stmt);
return true;
case PRAGMA_CILK_GRAINSIZE:
@@ -34099,7 +34114,7 @@ cp_parser_cilk_for (cp_parser *parser, t
tree clauses = build_omp_clause (EXPR_LOCATION (grain), OMP_CLAUSE_SCHEDULE);
OMP_CLAUSE_SCHEDULE_KIND (clauses) = OMP_CLAUSE_SCHEDULE_CILKFOR;
OMP_CLAUSE_SCHEDULE_CHUNK_EXPR (clauses) = grain;
- clauses = finish_omp_clauses (clauses);
+ clauses = finish_omp_clauses (clauses, false);
tree ret = cp_parser_omp_for_loop (parser, CILK_FOR, clauses, NULL);
if (ret)
@@ -1733,3 +1733,19 @@ cxx_omp_finish_clause (tree c, gimple_se
if (make_shared)
OMP_CLAUSE_CODE (c) = OMP_CLAUSE_SHARED;
}
+
+/* Return true if DECL's DECL_VALUE_EXPR (if any) should be
+ disregarded in OpenMP construct, because it is going to be
+ remapped during OpenMP lowering. SHARED is true if DECL
+ is going to be shared, false if it is going to be privatized. */
+
+bool
+cxx_omp_disregard_value_expr (tree decl, bool shared)
+{
+ return !shared
+ && VAR_P (decl)
+ && DECL_HAS_VALUE_EXPR_P (decl)
+ && DECL_ARTIFICIAL (decl)
+ && DECL_LANG_SPECIFIC (decl)
+ && DECL_OMP_PRIVATIZED_MEMBER (decl);
+}
@@ -8949,7 +8949,7 @@ can_complete_type_without_circularity (t
return 1;
}
-static tree tsubst_omp_clauses (tree, bool, tree, tsubst_flags_t, tree);
+static tree tsubst_omp_clauses (tree, bool, 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;
@@ -8998,10 +8998,10 @@ apply_late_template_attributes (tree *de
&& TREE_VALUE (t))
{
tree clauses = TREE_VALUE (TREE_VALUE (t));
- clauses = tsubst_omp_clauses (clauses, true, args,
+ clauses = tsubst_omp_clauses (clauses, true, false, args,
complain, in_decl);
c_omp_declare_simd_clauses_to_decls (*decl_p, clauses);
- clauses = finish_omp_clauses (clauses);
+ clauses = finish_omp_clauses (clauses, false);
tree parms = DECL_ARGUMENTS (*decl_p);
clauses
= c_omp_declare_simd_clauses_to_numbers (parms, clauses);
@@ -13432,7 +13432,7 @@ tsubst_copy (tree t, tree args, tsubst_f
/* Like tsubst_copy, but specifically for OpenMP clauses. */
static tree
-tsubst_omp_clauses (tree clauses, bool declare_simd,
+tsubst_omp_clauses (tree clauses, bool declare_simd, bool allow_fields,
tree args, tsubst_flags_t complain, tree in_decl)
{
tree new_clauses = NULL, nc, oc;
@@ -13532,11 +13532,80 @@ tsubst_omp_clauses (tree clauses, bool d
default:
gcc_unreachable ();
}
+ if (allow_fields)
+ switch (OMP_CLAUSE_CODE (nc))
+ {
+ case OMP_CLAUSE_PRIVATE:
+ case OMP_CLAUSE_FIRSTPRIVATE:
+ case OMP_CLAUSE_LASTPRIVATE:
+ case OMP_CLAUSE_COPYPRIVATE:
+ case OMP_CLAUSE_LINEAR:
+ case OMP_CLAUSE_REDUCTION:
+ /* tsubst_expr on SCOPE_REF results in returning
+ finish_non_static_data_member result. Undo that here. */
+ if (TREE_CODE (OMP_CLAUSE_DECL (oc)) == SCOPE_REF
+ && (TREE_CODE (TREE_OPERAND (OMP_CLAUSE_DECL (oc), 1))
+ == IDENTIFIER_NODE))
+ {
+ tree t = OMP_CLAUSE_DECL (nc);
+ if (TREE_CODE (t) == INDIRECT_REF)
+ t = TREE_OPERAND (t, 0);
+ if (TREE_CODE (t) != COMPONENT_REF)
+ {
+ if (VAR_P (t)
+ && DECL_LANG_SPECIFIC (t)
+ && DECL_OMP_PRIVATIZED_MEMBER (t))
+ OMP_CLAUSE_DECL (nc) = t;
+ break;
+ }
+ tree v = t;
+ while (v)
+ switch (TREE_CODE (v))
+ {
+ case COMPONENT_REF:
+ case MEM_REF:
+ case INDIRECT_REF:
+ CASE_CONVERT:
+ case POINTER_PLUS_EXPR:
+ v = TREE_OPERAND (v, 0);
+ continue;
+ case PARM_DECL:
+ if (DECL_CONTEXT (v) == current_function_decl
+ && DECL_ARTIFICIAL (v)
+ && DECL_NAME (v) == this_identifier)
+ OMP_CLAUSE_DECL (nc) = TREE_OPERAND (t, 1);
+ /* FALLTHRU */
+ default:
+ v = NULL_TREE;
+ break;
+ }
+ }
+ else if (VAR_P (OMP_CLAUSE_DECL (oc))
+ && DECL_HAS_VALUE_EXPR_P (OMP_CLAUSE_DECL (oc))
+ && DECL_ARTIFICIAL (OMP_CLAUSE_DECL (oc))
+ && DECL_LANG_SPECIFIC (OMP_CLAUSE_DECL (oc))
+ && DECL_OMP_PRIVATIZED_MEMBER (OMP_CLAUSE_DECL (oc)))
+ {
+ tree decl = OMP_CLAUSE_DECL (nc);
+ if (TREE_CODE (decl) == INDIRECT_REF)
+ decl = TREE_OPERAND (decl, 0);
+ if (VAR_P (decl))
+ {
+ if (!DECL_LANG_SPECIFIC (decl))
+ retrofit_lang_decl (decl);
+ DECL_OMP_PRIVATIZED_MEMBER (decl) = 1;
+ OMP_CLAUSE_DECL (nc) = decl;
+ }
+ }
+ break;
+ default:
+ break;
+ }
}
new_clauses = nreverse (new_clauses);
if (!declare_simd)
- new_clauses = finish_omp_clauses (new_clauses);
+ new_clauses = finish_omp_clauses (new_clauses, allow_fields);
return new_clauses;
}
@@ -13676,7 +13745,7 @@ tsubst_omp_for_iterator (tree t, int i,
{
c = build_omp_clause (input_location, OMP_CLAUSE_PRIVATE);
OMP_CLAUSE_DECL (c) = decl;
- c = finish_omp_clauses (c);
+ c = finish_omp_clauses (c, false);
if (c)
{
OMP_CLAUSE_CHAIN (c) = *clauses;
@@ -14137,20 +14206,24 @@ tsubst_expr (tree t, tree args, tsubst_f
break;
case OMP_PARALLEL:
- tmp = tsubst_omp_clauses (OMP_PARALLEL_CLAUSES (t), false,
+ r = push_omp_privatization_clauses ();
+ tmp = tsubst_omp_clauses (OMP_PARALLEL_CLAUSES (t), false, true,
args, complain, in_decl);
stmt = begin_omp_parallel ();
RECUR (OMP_PARALLEL_BODY (t));
OMP_PARALLEL_COMBINED (finish_omp_parallel (tmp, stmt))
= OMP_PARALLEL_COMBINED (t);
+ pop_omp_privatization_clauses (r);
break;
case OMP_TASK:
- tmp = tsubst_omp_clauses (OMP_TASK_CLAUSES (t), false,
+ r = push_omp_privatization_clauses ();
+ tmp = tsubst_omp_clauses (OMP_TASK_CLAUSES (t), false, true,
args, complain, in_decl);
stmt = begin_omp_task ();
RECUR (OMP_TASK_BODY (t));
finish_omp_task (tmp, stmt);
+ pop_omp_privatization_clauses (r);
break;
case OMP_FOR:
@@ -14165,7 +14238,8 @@ tsubst_expr (tree t, tree args, tsubst_f
tree incrv = NULL_TREE;
int i;
- clauses = tsubst_omp_clauses (OMP_FOR_CLAUSES (t), false,
+ r = push_omp_privatization_clauses ();
+ clauses = tsubst_omp_clauses (OMP_FOR_CLAUSES (t), false, true,
args, complain, in_decl);
if (OMP_FOR_INIT (t) != NULL_TREE)
{
@@ -14206,13 +14280,15 @@ tsubst_expr (tree t, tree args, tsubst_f
}
add_stmt (finish_omp_structured_block (stmt));
+ pop_omp_privatization_clauses (r);
}
break;
case OMP_SECTIONS:
case OMP_SINGLE:
case OMP_TEAMS:
- tmp = tsubst_omp_clauses (OMP_CLAUSES (t), false,
+ r = push_omp_privatization_clauses ();
+ tmp = tsubst_omp_clauses (OMP_CLAUSES (t), false, true,
args, complain, in_decl);
stmt = push_stmt_list ();
RECUR (OMP_BODY (t));
@@ -14222,11 +14298,12 @@ tsubst_expr (tree t, tree args, tsubst_f
OMP_BODY (t) = stmt;
OMP_CLAUSES (t) = tmp;
add_stmt (t);
+ pop_omp_privatization_clauses (r);
break;
case OMP_TARGET_DATA:
case OMP_TARGET:
- tmp = tsubst_omp_clauses (OMP_CLAUSES (t), false,
+ tmp = tsubst_omp_clauses (OMP_CLAUSES (t), false, false,
args, complain, in_decl);
keep_next_level (true);
stmt = begin_omp_structured_block ();
@@ -14241,7 +14318,7 @@ tsubst_expr (tree t, tree args, tsubst_f
break;
case OMP_TARGET_UPDATE:
- tmp = tsubst_omp_clauses (OMP_TARGET_UPDATE_CLAUSES (t), false,
+ tmp = tsubst_omp_clauses (OMP_TARGET_UPDATE_CLAUSES (t), false, false,
args, complain, in_decl);
t = copy_node (t);
OMP_TARGET_UPDATE_CLAUSES (t) = tmp;
@@ -2023,6 +2023,7 @@ struct GTY(()) lang_decl_base {
unsigned repo_available_p : 1; /* var or fn */
unsigned threadprivate_or_deleted_p : 1; /* var or fn */
unsigned anticipated_p : 1; /* fn, type or template */
+ /* Reused as DECL_OMP_PRIVATIZED_MEMBER in var */
unsigned friend_attr : 1; /* fn, type or template */
unsigned template_conv_p : 1; /* var or template */
unsigned odr_used : 1; /* var or fn */
@@ -3307,6 +3308,11 @@ more_aggr_init_expr_args_p (const aggr_i
(DECL_LANG_SPECIFIC (TYPE_FUNCTION_OR_TEMPLATE_DECL_CHECK (NODE)) \
->u.base.anticipated_p)
+/* True for artificial decls added for OpenMP privatized non-static
+ data members. */
+#define DECL_OMP_PRIVATIZED_MEMBER(NODE) \
+ (DECL_LANG_SPECIFIC (VAR_DECL_CHECK (NODE))->u.base.anticipated_p)
+
/* Nonzero if NODE is a FUNCTION_DECL which was declared as a friend
within a class but has not been declared in the surrounding scope.
The function is invisible except via argument dependent lookup. */
@@ -5988,7 +5994,11 @@ 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 tree finish_omp_clauses (tree, bool);
+extern tree push_omp_privatization_clauses (void);
+extern void pop_omp_privatization_clauses (tree);
+extern void save_omp_privatization_clauses (vec<tree> &);
+extern void restore_omp_privatization_clauses (vec<tree> &);
extern void finish_omp_threadprivate (tree);
extern tree begin_omp_structured_block (void);
extern tree finish_omp_structured_block (tree);
@@ -6372,6 +6382,7 @@ extern tree cxx_omp_clause_assign_op (t
extern tree cxx_omp_clause_dtor (tree, tree);
extern void cxx_omp_finish_clause (tree, gimple_seq *);
extern bool cxx_omp_privatize_by_reference (const_tree);
+extern bool cxx_omp_disregard_value_expr (tree, bool);
/* in name-lookup.c */
extern void suggest_alternatives_for (location_t, tree);
@@ -150,6 +150,8 @@ extern void cp_common_init_ts (void);
#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_OMP_DISREGARD_VALUE_EXPR
+#define LANG_HOOKS_OMP_DISREGARD_VALUE_EXPR cxx_omp_disregard_value_expr
#undef LANG_HOOKS_EH_USE_CXA_END_CLEANUP
#define LANG_HOOKS_EH_USE_CXA_END_CLEANUP true
@@ -77,6 +77,11 @@ static tree maybe_convert_cond (tree);
static tree finalize_nrv_r (tree *, int *, void *);
static tree capture_decltype (tree);
+/* Used for OpenMP non-static data member privatization. */
+
+static hash_map<tree, tree> *omp_private_member_map;
+static vec<tree> omp_private_member_vec;
+
/* Deferred Access Checking Overview
---------------------------------
@@ -1716,6 +1721,8 @@ tree
finish_non_static_data_member (tree decl, tree object, tree qualifying_scope)
{
gcc_assert (TREE_CODE (decl) == FIELD_DECL);
+ bool try_omp_private = !object && omp_private_member_map;
+ tree ret;
if (!object)
{
@@ -1767,17 +1774,17 @@ finish_non_static_data_member (tree decl
type = cp_build_qualified_type (type, quals);
}
- return (convert_from_reference
+ ret = (convert_from_reference
(build_min (COMPONENT_REF, type, object, decl, NULL_TREE)));
}
/* If PROCESSING_TEMPLATE_DECL is nonzero here, then
QUALIFYING_SCOPE is also non-null. Wrap this in a SCOPE_REF
for now. */
else if (processing_template_decl)
- return build_qualified_name (TREE_TYPE (decl),
- qualifying_scope,
- decl,
- /*template_p=*/false);
+ ret = build_qualified_name (TREE_TYPE (decl),
+ qualifying_scope,
+ decl,
+ /*template_p=*/false);
else
{
tree access_type = TREE_TYPE (object);
@@ -1794,11 +1801,18 @@ finish_non_static_data_member (tree decl
&binfo);
}
- return build_class_member_access_expr (object, decl,
- /*access_path=*/NULL_TREE,
- /*preserve_reference=*/false,
- tf_warning_or_error);
+ ret = build_class_member_access_expr (object, decl,
+ /*access_path=*/NULL_TREE,
+ /*preserve_reference=*/false,
+ tf_warning_or_error);
+ }
+ if (try_omp_private)
+ {
+ tree *v = omp_private_member_map->get (decl);
+ if (v)
+ ret = convert_from_reference (*v);
}
+ return ret;
}
/* If we are currently parsing a template and we encountered a typedef
@@ -5296,7 +5310,7 @@ finish_omp_reduction_clause (tree c, boo
Remove any elements from the list that are invalid. */
tree
-finish_omp_clauses (tree clauses)
+finish_omp_clauses (tree clauses, bool allow_fields)
{
bitmap_head generic_head, firstprivate_head, lastprivate_head;
bitmap_head aligned_head;
@@ -5314,21 +5328,26 @@ finish_omp_clauses (tree clauses)
for (pc = &clauses, c = clauses; c ; c = *pc)
{
bool remove = false;
+ bool field_ok = false;
switch (OMP_CLAUSE_CODE (c))
{
case OMP_CLAUSE_SHARED:
goto check_dup_generic;
case OMP_CLAUSE_PRIVATE:
+ field_ok = allow_fields;
goto check_dup_generic;
case OMP_CLAUSE_REDUCTION:
+ field_ok = allow_fields;
goto check_dup_generic;
case OMP_CLAUSE_COPYPRIVATE:
copyprivate_seen = true;
+ field_ok = allow_fields;
goto check_dup_generic;
case OMP_CLAUSE_COPYIN:
goto check_dup_generic;
case OMP_CLAUSE_LINEAR:
+ field_ok = allow_fields;
t = OMP_CLAUSE_DECL (c);
if (!type_dependent_expression_p (t))
{
@@ -5391,7 +5410,8 @@ finish_omp_clauses (tree clauses)
goto check_dup_generic;
check_dup_generic:
t = OMP_CLAUSE_DECL (c);
- if (!VAR_P (t) && TREE_CODE (t) != PARM_DECL)
+ if (!VAR_P (t) && TREE_CODE (t) != PARM_DECL
+ && (!field_ok || TREE_CODE (t) != FIELD_DECL))
{
if (processing_template_decl)
break;
@@ -5412,11 +5432,70 @@ finish_omp_clauses (tree clauses)
}
else
bitmap_set_bit (&generic_head, DECL_UID (t));
+ if (!field_ok)
+ break;
+ handle_field_decl:
+ if (!remove && TREE_CODE (t) == FIELD_DECL)
+ {
+ tree m = finish_non_static_data_member (t, NULL_TREE, NULL_TREE);
+ if (m == error_mark_node)
+ {
+ remove = true;
+ break;
+ }
+ if (!omp_private_member_map)
+ omp_private_member_map = new hash_map<tree, tree>;
+ if (TREE_CODE (TREE_TYPE (t)) == REFERENCE_TYPE)
+ {
+ gcc_assert (TREE_CODE (m) == INDIRECT_REF);
+ m = TREE_OPERAND (m, 0);
+ }
+ tree &v = omp_private_member_map->get_or_insert (t);
+ if (v == NULL_TREE)
+ {
+ v = create_temporary_var (TREE_TYPE (m));
+ if (!DECL_LANG_SPECIFIC (v))
+ retrofit_lang_decl (v);
+ DECL_OMP_PRIVATIZED_MEMBER (v) = 1;
+ SET_DECL_VALUE_EXPR (v, m);
+ DECL_HAS_VALUE_EXPR_P (v) = 1;
+ omp_private_member_vec.safe_push (t);
+ }
+ OMP_CLAUSE_DECL (c) = v;
+ }
+ else if (!remove
+ && VAR_P (t)
+ && DECL_HAS_VALUE_EXPR_P (t)
+ && DECL_ARTIFICIAL (t)
+ && DECL_LANG_SPECIFIC (t)
+ && DECL_OMP_PRIVATIZED_MEMBER (t))
+ {
+ tree f = DECL_VALUE_EXPR (t);
+ if (TREE_CODE (f) == INDIRECT_REF)
+ f = TREE_OPERAND (f, 0);
+ if (TREE_CODE (f) == COMPONENT_REF)
+ {
+ f = TREE_OPERAND (f, 1);
+ gcc_assert (TREE_CODE (f) == FIELD_DECL);
+ if (!omp_private_member_map)
+ omp_private_member_map = new hash_map<tree, tree>;
+ tree &v = omp_private_member_map->get_or_insert (f);
+ if (v == NULL_TREE)
+ {
+ v = t;
+ omp_private_member_vec.safe_push (f);
+ /* Signal that we don't want to create
+ DECL_EXPR for this dummy var. */
+ omp_private_member_vec.safe_push (integer_zero_node);
+ }
+ }
+ }
break;
case OMP_CLAUSE_FIRSTPRIVATE:
t = OMP_CLAUSE_DECL (c);
- if (!VAR_P (t) && TREE_CODE (t) != PARM_DECL)
+ if (!VAR_P (t) && TREE_CODE (t) != PARM_DECL
+ && (!allow_fields || TREE_CODE (t) != FIELD_DECL))
{
if (processing_template_decl)
break;
@@ -5434,11 +5513,12 @@ finish_omp_clauses (tree clauses)
}
else
bitmap_set_bit (&firstprivate_head, DECL_UID (t));
- break;
+ goto handle_field_decl;
case OMP_CLAUSE_LASTPRIVATE:
t = OMP_CLAUSE_DECL (c);
- if (!VAR_P (t) && TREE_CODE (t) != PARM_DECL)
+ if (!VAR_P (t) && TREE_CODE (t) != PARM_DECL
+ && (!allow_fields || TREE_CODE (t) != FIELD_DECL))
{
if (processing_template_decl)
break;
@@ -5456,7 +5536,7 @@ finish_omp_clauses (tree clauses)
}
else
bitmap_set_bit (&lastprivate_head, DECL_UID (t));
- break;
+ goto handle_field_decl;
case OMP_CLAUSE_IF:
t = OMP_CLAUSE_IF_EXPR (c);
@@ -6057,6 +6137,7 @@ finish_omp_clauses (tree clauses)
need_implicitly_determined = true;
break;
case OMP_CLAUSE_REDUCTION:
+ case OMP_CLAUSE_LINEAR:
need_implicitly_determined = true;
break;
case OMP_CLAUSE_COPYPRIVATE:
@@ -6166,8 +6247,25 @@ finish_omp_clauses (tree clauses)
}
if (share_name)
{
- error ("%qE is predetermined %qs for %qs",
- t, share_name, omp_clause_code_name[OMP_CLAUSE_CODE (c)]);
+ tree pt = t;
+ if (VAR_P (t)
+ && DECL_HAS_VALUE_EXPR_P (t)
+ && DECL_ARTIFICIAL (t)
+ && DECL_LANG_SPECIFIC (t)
+ && DECL_OMP_PRIVATIZED_MEMBER (t))
+ {
+ tree f = DECL_VALUE_EXPR (t);
+ if (TREE_CODE (f) == INDIRECT_REF)
+ f = TREE_OPERAND (f, 0);
+ if (TREE_CODE (f) == COMPONENT_REF)
+ {
+ f = TREE_OPERAND (f, 1);
+ gcc_assert (TREE_CODE (f) == FIELD_DECL);
+ pt = f;
+ }
+ }
+ error ("%qE is predetermined %qs for %qs", pt, share_name,
+ omp_clause_code_name[OMP_CLAUSE_CODE (c)]);
remove = true;
}
}
@@ -6205,6 +6303,108 @@ finish_omp_clauses (tree clauses)
return clauses;
}
+/* Start processing OpenMP clauses that can include any
+ privatization clauses for non-static data members. */
+
+tree
+push_omp_privatization_clauses (void)
+{
+ if (omp_private_member_map)
+ omp_private_member_vec.safe_push (error_mark_node);
+ return push_stmt_list ();
+}
+
+/* Revert remapping of any non-static data members since
+ the last push_omp_privatization_clauses () call. */
+
+void
+pop_omp_privatization_clauses (tree stmt)
+{
+ stmt = pop_stmt_list (stmt);
+ if (omp_private_member_map)
+ {
+ while (!omp_private_member_vec.is_empty ())
+ {
+ tree t = omp_private_member_vec.pop ();
+ if (t == error_mark_node)
+ {
+ add_stmt (stmt);
+ return;
+ }
+ bool no_decl_expr = t == integer_zero_node;
+ if (no_decl_expr)
+ t = omp_private_member_vec.pop ();
+ tree *v = omp_private_member_map->get (t);
+ gcc_assert (v);
+ if (!no_decl_expr)
+ add_decl_expr (*v);
+ omp_private_member_map->remove (t);
+ }
+ delete omp_private_member_map;
+ omp_private_member_map = NULL;
+ }
+ add_stmt (stmt);
+}
+
+/* Remember OpenMP privatization clauses mapping and clear it.
+ Used for lambdas. */
+
+void
+save_omp_privatization_clauses (vec<tree> &save)
+{
+ save = vNULL;
+ if (!omp_private_member_map)
+ return;
+ while (!omp_private_member_vec.is_empty ())
+ {
+ tree t = omp_private_member_vec.pop ();
+ if (t == error_mark_node)
+ {
+ save.safe_push (t);
+ continue;
+ }
+ tree n = t;
+ if (t == integer_zero_node)
+ t = omp_private_member_vec.pop ();
+ tree *v = omp_private_member_map->get (t);
+ gcc_assert (v);
+ save.safe_push (*v);
+ save.safe_push (t);
+ if (n != t)
+ save.safe_push (n);
+ }
+ delete omp_private_member_map;
+ omp_private_member_map = NULL;
+}
+
+/* Restore OpenMP privatization clauses mapping saved by the
+ above function. */
+
+void
+restore_omp_privatization_clauses (vec<tree> &save)
+{
+ gcc_assert (omp_private_member_vec.is_empty ());
+ if (save.is_empty ())
+ return;
+ omp_private_member_map = new hash_map <tree, tree>;
+ while (!save.is_empty ())
+ {
+ tree t = save.pop ();
+ tree n = t;
+ if (t != error_mark_node)
+ {
+ if (t == integer_zero_node)
+ t = save.pop ();
+ tree &v = omp_private_member_map->get_or_insert (t);
+ v = save.pop ();
+ }
+ omp_private_member_vec.safe_push (t);
+ if (n != t)
+ omp_private_member_vec.safe_push (n);
+ }
+ save.release ();
+}
+
/* For all variables in the tree_list VARS, mark them as thread local. */
void
@@ -6954,7 +7154,7 @@ finish_omp_for (location_t locus, enum t
OMP_CLAUSE_OPERAND (c, 0)
= cilk_for_number_of_iterations (omp_for);
OMP_CLAUSE_CHAIN (c) = clauses;
- OMP_PARALLEL_CLAUSES (omp_par) = finish_omp_clauses (c);
+ OMP_PARALLEL_CLAUSES (omp_par) = finish_omp_clauses (c, false);
add_stmt (omp_par);
return omp_par;
}
@@ -9,22 +9,22 @@ struct T
void T::test()
{
- #pragma omp parallel private(n) // { dg-error "T::n" }
+ #pragma omp parallel private(n)
n = 1;
#pragma omp parallel shared(n) // { dg-error "T::n" }
n = 1;
- #pragma omp parallel firstprivate(n) // { dg-error "T::n" }
+ #pragma omp parallel firstprivate(n)
n = 1;
- #pragma omp sections lastprivate(n) // { dg-error "T::n" }
+ #pragma omp sections lastprivate(n)
{ n = 1; }
- #pragma omp parallel reduction(+:n) // { dg-error "T::n" }
+ #pragma omp parallel reduction(+:n)
n = 1;
- #pragma omp single copyprivate(n) // { dg-error "T::n" }
+ #pragma omp single copyprivate(n)
n = 1;
#pragma omp parallel copyin(n) // { dg-error "T::n" }
@@ -0,0 +1,214 @@
+struct T { T () {}; virtual ~T () {}; int t; };
+struct S : virtual public T { int a; void foo (); };
+template <typename T>
+struct U { U () {}; virtual ~U () {}; T t; };
+template <typename T>
+struct V : virtual public U<T> { T a; void foo (); };
+
+void
+S::foo ()
+{
+#pragma omp parallel firstprivate (a, t)
+ {
+ int *q1 = &a;
+ int *q2 = &this->a;
+ int q3 = a;
+ int q4 = this->a;
+ int *q5 = &t;
+ int *q6 = &this->t;
+ int q7 = t;
+ int q8 = this->t;
+ int q9 = T::t;
+ int q10 = this->T::t;
+ int &q11 = a;
+ int &q12 = this->a;
+ int &q13 = t;
+ int &q14 = this->t;
+ int &q15 = S::a;
+ int &q16 = this->S::a;
+ int &q17 = T::t;
+ int &q18 = this->T::t;
+ }
+#pragma omp parallel private (a, t)
+ {
+ a = 7;
+ S::a += 9;
+ t = 10;
+ T::t += 11;
+ }
+#pragma omp parallel
+ {
+ #pragma omp sections lastprivate (S::a, T::t)
+ {
+ #pragma omp section
+ {
+ S::a = 6;
+ T::t = 8;
+ }
+ }
+ }
+#pragma omp parallel
+ {
+ #pragma omp for firstprivate (a, t) lastprivate (a, t)
+ for (int i = 0; i < 10; i++)
+ {
+ int q19 = a + t;
+ if (i == 9)
+ {
+ a = i;
+ T::t = i + 2;
+ }
+ }
+ }
+#pragma omp sections lastprivate (a, t)
+ {
+ #pragma omp section
+ {
+ a = 5;
+ t = 6;
+ }
+ }
+#pragma omp for firstprivate (a, t) lastprivate (a, t)
+ for (int i = 0; i < 10; i++)
+ {
+ int q20 = a + t;
+ if (i == 9)
+ {
+ a = i;
+ T::t = i + 2;
+ }
+ }
+#pragma omp parallel sections lastprivate (a, t)
+ {
+ #pragma omp section
+ {
+ a = 5;
+ t = 6;
+ }
+ }
+#pragma omp parallel
+ {
+ #pragma omp task firstprivate (a, t)
+ {
+ S::a++;
+ t++;
+ }
+ }
+#pragma omp parallel
+ {
+ #pragma omp taskloop firstprivate (a, t) lastprivate (t)
+ for (int i = 0; i < a; i++)
+ t++;
+ }
+#pragma omp taskloop firstprivate (a, t) lastprivate (t)
+ for (int i = 0; i < a; i++)
+ t++;
+}
+
+template <typename T>
+void
+V<T>::foo ()
+{
+#pragma omp parallel firstprivate (a, U<T>::t)
+ {
+ int *q1 = &a;
+ int *q2 = &this->a;
+ int q3 = a;
+ int q4 = this->a;
+ int *q5 = &(U<T>::t);
+ int *q6 = &this->U<T>::t;
+ int q7 = U<T>::t;
+ int q8 = this->U<T>::t;
+ int q9 = U<T>::t;
+ int q10 = this->U<T>::t;
+ int &q11 = a;
+ int &q12 = this->a;
+ int &q13 = U<T>::t;
+ int &q14 = this->U<T>::t;
+ int &q15 = V::a;
+ int &q16 = this->V::a;
+ int &q17 = U<T>::t;
+ int &q18 = this->U<T>::t;
+ }
+#pragma omp parallel private (a, U<T>::t)
+ {
+ a = 7;
+ V::a += 9;
+ U<T>::t = 10;
+ U<T>::t += 11;
+ }
+#pragma omp parallel
+ {
+ #pragma omp sections lastprivate (V::a, U<T>::t)
+ {
+ #pragma omp section
+ {
+ V::a = 6;
+ U<T>::t = 8;
+ }
+ }
+ }
+#pragma omp parallel
+ {
+ #pragma omp for firstprivate (a, U<T>::t) lastprivate (a, U<T>::t)
+ for (int i = 0; i < 10; i++)
+ {
+ int q19 = a + U<T>::t;
+ if (i == 9)
+ {
+ a = i;
+ U<T>::t = i + 2;
+ }
+ }
+ }
+#pragma omp sections lastprivate (a, U<T>::t)
+ {
+ #pragma omp section
+ {
+ a = 5;
+ U<T>::t = 6;
+ }
+ }
+#pragma omp for firstprivate (a, U<T>::t) lastprivate (a, U<T>::t)
+ for (int i = 0; i < 10; i++)
+ {
+ int q20 = a + U<T>::t;
+ if (i == 9)
+ {
+ a = i;
+ U<T>::t = i + 2;
+ }
+ }
+#pragma omp parallel sections lastprivate (a, U<T>::t)
+ {
+ #pragma omp section
+ {
+ a = 5;
+ U<T>::t = 6;
+ }
+ }
+#pragma omp parallel
+ {
+ #pragma omp task firstprivate (a, U<T>::t)
+ {
+ V::a++;
+ U<T>::t++;
+ }
+ }
+#pragma omp parallel
+ {
+ #pragma omp taskloop firstprivate (a, U<T>::t) lastprivate (U<T>::t)
+ for (int i = 0; i < a; i++)
+ U<T>::t++;
+ }
+#pragma omp taskloop firstprivate (a, U<T>::t) lastprivate (U<T>::t)
+ for (int i = 0; i < a; i++)
+ U<T>::t++;
+}
+
+void
+bar ()
+{
+ V<int> v;
+ v.foo ();
+}
@@ -0,0 +1,139 @@
+// { dg-do compile }
+// { dg-options "-fopenmp" }
+
+int d;
+
+struct A
+{
+ A () : a(2), b(3), c(d) {}
+ int a;
+ A (const A &);
+ A &operator= (const A &);
+ const A &operator= (const A &) const;
+ mutable int b;
+ int &c;
+};
+
+struct B : public A
+{
+ B () : h(5) {}
+ ~B ();
+ B (const B &);
+ A e;
+ mutable A f;
+ const A g;
+ const int h;
+ int m1 ();
+ int m2 ();
+ int m3 () const;
+ int m4 () const;
+};
+
+int
+B::m1 ()
+{
+ #pragma omp parallel private (a, b, c, e, f, g)
+ ;
+ #pragma omp parallel firstprivate (a, b, c, e, f, g)
+ ;
+ #pragma omp parallel for lastprivate (a, b, c, e, f, g)
+ for (int i = 0; i < 10; i++)
+ ;
+ #pragma omp simd linear (a, b, c : 1)
+ for (int i = 0; i < 10; i++)
+ {
+ a++;
+ b++;
+ c++;
+ }
+ return 0;
+}
+
+int
+B::m2 ()
+{
+ #pragma omp parallel private (h) // { dg-error "is predetermined .shared. for .private." }
+ ;
+ #pragma omp parallel firstprivate (h)
+ ;
+ #pragma omp parallel for lastprivate (h) // { dg-error "is predetermined .shared. for .lastprivate." }
+ for (int i = 0; i < 10; i++)
+ ;
+ #pragma omp simd linear (h : 1) // { dg-error "is predetermined .shared. for .linear." }
+ for (int i = 0; i < 10; i++)
+ ;
+ #pragma omp parallel shared (a) // { dg-error "is not a variable in clause" }
+ ;
+ #pragma omp parallel shared (b) // { dg-error "is not a variable in clause" }
+ ;
+ #pragma omp parallel shared (c) // { dg-error "is not a variable in clause" }
+ ;
+ #pragma omp parallel shared (e) // { dg-error "is not a variable in clause" }
+ ;
+ #pragma omp parallel shared (f) // { dg-error "is not a variable in clause" }
+ ;
+ #pragma omp parallel shared (g) // { dg-error "is not a variable in clause" }
+ ;
+ #pragma omp parallel shared (h) // { dg-error "is not a variable in clause" }
+ ;
+ return 0;
+}
+
+int
+B::m3 () const
+{
+ #pragma omp parallel private (b, c, e, f, g)
+ ;
+ #pragma omp parallel firstprivate (b, c, e, f, g)
+ ;
+ #pragma omp parallel for lastprivate (b, c, e, f, g)
+ for (int i = 0; i < 10; i++)
+ ;
+ #pragma omp simd linear (b, c : 1)
+ for (int i = 0; i < 10; i++)
+ {
+ b++;
+ c++;
+ }
+ return 0;
+}
+
+int
+B::m4 () const
+{
+ #pragma omp parallel private (a) // { dg-error "is predetermined .shared. for .private." }
+ ;
+ #pragma omp parallel firstprivate (a)
+ ;
+ #pragma omp parallel for lastprivate (a) // { dg-error "is predetermined .shared. for .lastprivate." }
+ for (int i = 0; i < 10; i++)
+ ;
+ #pragma omp simd linear (a : 1) // { dg-error "is predetermined .shared. for .linear." }
+ for (int i = 0; i < 10; i++)
+ ;
+ #pragma omp parallel private (h) // { dg-error "is predetermined .shared. for .private." }
+ ;
+ #pragma omp parallel firstprivate (h)
+ ;
+ #pragma omp parallel for lastprivate (h) // { dg-error "is predetermined .shared. for .lastprivate." }
+ for (int i = 0; i < 10; i++)
+ ;
+ #pragma omp simd linear (h : 1) // { dg-error "is predetermined .shared. for .linear." }
+ for (int i = 0; i < 10; i++)
+ ;
+ #pragma omp parallel shared (a) // { dg-error "is not a variable in clause" }
+ ;
+ #pragma omp parallel shared (b) // { dg-error "is not a variable in clause" }
+ ;
+ #pragma omp parallel shared (c) // { dg-error "is not a variable in clause" }
+ ;
+ #pragma omp parallel shared (e) // { dg-error "is not a variable in clause" }
+ ;
+ #pragma omp parallel shared (f) // { dg-error "is not a variable in clause" }
+ ;
+ #pragma omp parallel shared (g) // { dg-error "is not a variable in clause" }
+ ;
+ #pragma omp parallel shared (h) // { dg-error "is not a variable in clause" }
+ ;
+ return 0;
+}
@@ -0,0 +1,70 @@
+#include <omp.h>
+
+__attribute__((noinline, noclone)) void
+foo (int &b)
+{
+#pragma omp parallel
+ {
+ bool f = false;
+ #pragma omp taskloop firstprivate (b, f)
+ for (int i = 0; i < 30; i++)
+ {
+ int q = omp_get_thread_num ();
+ if (!f)
+ {
+ if (b != 2)
+ __builtin_abort ();
+ }
+ else if (b != 8 * q)
+ __builtin_abort ();
+ b = 8 * q;
+ f = true;
+ }
+ }
+ int n;
+#pragma omp parallel
+ {
+ bool f = false;
+ #pragma omp taskloop firstprivate (f) lastprivate (b, n)
+ for (int i = 0; i < 30; i++)
+ {
+ int q = omp_get_thread_num ();
+ if (f && b != 8 * q)
+ __builtin_abort ();
+ b = 8 * q;
+ n = q;
+ f = true;
+ }
+ }
+ if (b != 8 * n)
+ __builtin_abort ();
+ b = 9;
+#pragma omp parallel
+ {
+ bool f = false;
+ #pragma omp taskloop firstprivate (b, f) lastprivate (b, n)
+ for (int i = 0; i < 30; i++)
+ {
+ int q = omp_get_thread_num ();
+ if (!f)
+ {
+ if (b != 9)
+ __builtin_abort ();
+ }
+ else if (b != 11 * q)
+ __builtin_abort ();
+ b = 11 * q;
+ n = q;
+ f = true;
+ }
+ }
+ if (b != 11 * n)
+ __builtin_abort ();
+}
+
+int
+main ()
+{
+ int b = 2;
+ foo (b);
+}
@@ -0,0 +1,192 @@
+// { dg-do run }
+// { dg-options "-O2 -fopenmp" }
+
+#include <omp.h>
+
+struct R { R () {}; ~R () {}; int r; };
+struct T { T () {}; virtual ~T () {}; int t; };
+int c;
+struct A : public R, virtual public T { A () : b(c) {} int a; int &b; void m1 (); };
+
+void
+take (int &a, int &b, int &c, int &d)
+{
+ asm volatile ("" : : "g" (&a), "g" (&b), "g" (&c), "g" (&d) : "memory");
+}
+
+void
+A::m1 ()
+{
+ #pragma omp parallel private (a, r, T::t, A::b)
+ {
+ int q = omp_get_thread_num ();
+ a = q;
+ r = 2 * q;
+ t = 3 * q;
+ b = 4 * q;
+ take (a, r, t, b);
+ #pragma omp barrier
+ if (A::a != q || R::r != 2 * q || T::t != 3 * q || A::b != 4 * q)
+ __builtin_abort ();
+ }
+ a = 7;
+ r = 8;
+ t = 9;
+ b = 10;
+ #pragma omp parallel firstprivate (A::a, R::r, t, b)
+ {
+ int q = omp_get_thread_num ();
+ take (A::a, R::r, T::t, A::b);
+ if (a != 7 || r != 8 || t != 9 || b != 10)
+ __builtin_abort ();
+ A::a = 5 * q;
+ R::r = 6 * q;
+ T::t = 7 * q;
+ A::b = 8 * q;
+ take (a, r, t, b);
+ #pragma omp barrier
+ if (a != 5 * q || r != 6 * q || t != 7 * q || b != 8 * q)
+ __builtin_abort ();
+ }
+ bool f = false;
+ a = -5;
+ b = -4;
+ r = -3;
+ t = -2;
+ int n;
+ #pragma omp parallel for firstprivate (a, T::t, b, f) lastprivate (A::a, r, t, n)
+ for (int i = 0; i < omp_get_num_threads (); i++)
+ {
+ int q = omp_get_thread_num ();
+ if (!f)
+ {
+ if (A::a != -5 || A::b != -4 || T::t != -2)
+ __builtin_abort ();
+ }
+ else if (a != q || b != 2 * q || r != 3 * q || t != 4 * q)
+ __builtin_abort ();
+ take (a, r, t, b);
+ A::a = q;
+ A::b = 2 * q;
+ R::r = 3 * q;
+ T::t = 4 * q;
+ n = q;
+ f = true;
+ }
+ if (a != n || r != 3 * n || T::t != 4 * n)
+ __builtin_abort ();
+ b = 8;
+ #pragma omp parallel
+ #pragma omp single
+ for (int i = 0; i < 5; i++)
+ #pragma omp task firstprivate (t, b, n) private (a, R::r)
+ {
+ if (t != 4 * n || b != 8)
+ __builtin_abort ();
+ a = 9;
+ r = 8;
+ t = 12;
+ b = 18;
+ take (a, r, t, b);
+ if (a != 9 || r != 8 || t != 12 || b != 18)
+ __builtin_abort ();
+ }
+ a = 1;
+ b = 2;
+ R::r = 3;
+ t = 4;
+ #pragma omp parallel private (f)
+ {
+ f = false;
+ #pragma omp single
+ #pragma omp taskloop firstprivate (r, T::t, b, f) lastprivate (a, t, b, n)
+ for (int i = 0; i < 30; i++)
+ {
+ int q = omp_get_thread_num ();
+ if (!f)
+ {
+ if (R::r != 3 || A::b != 2 || T::t != 4)
+ __builtin_abort ();
+ }
+ else if (a != 7 * q || b != 8 * q || r != 9 * q || t != 10 * q)
+ __builtin_abort ();
+ take (a, r, t, b);
+ A::a = 7 * q;
+ A::b = 8 * q;
+ R::r = 9 * q;
+ T::t = 10 * q;
+ n = q;
+ f = true;
+ }
+ }
+ if (a != 7 * n || b != 8 * n || t != 10 * n)
+ __builtin_abort ();
+ a = 1;
+ b = 2;
+ R::r = 3;
+ t = 4;
+ #pragma omp parallel private (f)
+ {
+ f = false;
+ #pragma omp single
+ #pragma omp taskloop firstprivate (r, T::t, b, A::a, f)
+ for (int i = 0; i < 30; i++)
+ {
+ int q = omp_get_thread_num ();
+ if (!f)
+ {
+ if (A::a != 1 || R::r != 3 || A::b != 2 || T::t != 4)
+ __builtin_abort ();
+ }
+ else if (a != 7 * q || b != 8 * q || r != 9 * q || t != 10 * q)
+ __builtin_abort ();
+ take (a, r, t, b);
+ A::a = 7 * q;
+ A::b = 8 * q;
+ R::r = 9 * q;
+ T::t = 10 * q;
+ f = true;
+ }
+ }
+ #pragma omp parallel private (f)
+ {
+ f = false;
+ #pragma omp single
+ #pragma omp taskloop lastprivate (a, t, b, n)
+ for (int i = 0; i < 30; i++)
+ {
+ int q = omp_get_thread_num ();
+ if (f && (a != 7 * q || b != 8 * q || r != 9 * q || t != 10 * q))
+ __builtin_abort ();
+ take (a, r, t, b);
+ A::a = 7 * q;
+ A::b = 8 * q;
+ R::r = 9 * q;
+ T::t = 10 * q;
+ n = q;
+ f = true;
+ }
+ }
+ if (a != 7 * n || b != 8 * n || t != 10 * n)
+ __builtin_abort ();
+ #pragma omp parallel private (a, T::t, A::b, r)
+ {
+ int q = omp_get_thread_num ();
+ a = q;
+ b = 2 * q;
+ r = 3 * q;
+ t = 4 * q;
+ take (a, b, r, t);
+ #pragma omp single copyprivate (A::a, t, b, R::r)
+ n = q;
+ if (a != n || b != 2 * n || r != 3 * n || t != 4 * n)
+ __builtin_abort ();
+ }
+}
+
+int
+main ()
+{
+ A a;
+ a.m1 ();
+}
@@ -0,0 +1,197 @@
+// { dg-do run }
+// { dg-options "-O2 -fopenmp" }
+
+#include <omp.h>
+
+int c, d, e;
+struct R { R () {}; ~R () {}; int r; };
+template <typename Q>
+struct T { T () : t(d) {}; virtual ~T () {}; Q t; };
+template <typename Q>
+struct A : public R, virtual public T<Q> { A () : b(c), a(e) {} Q a; int &b; void m1 (); };
+
+void
+take (int &a, int &b, int &c, int &d)
+{
+ asm volatile ("" : : "g" (&a), "g" (&b), "g" (&c), "g" (&d) : "memory");
+}
+
+template <typename Q>
+void
+A<Q>::m1 ()
+{
+ #pragma omp parallel private (a, r, T<Q>::t, A::b)
+ {
+ int q = omp_get_thread_num ();
+ a = q;
+ r = 2 * q;
+ T<Q>::t = 3 * q;
+ b = 4 * q;
+ take (a, r, T<Q>::t, b);
+ #pragma omp barrier
+ if (A::a != q || R::r != 2 * q || T<Q>::t != 3 * q || A::b != 4 * q)
+ __builtin_abort ();
+ }
+ a = 7;
+ r = 8;
+ T<Q>::t = 9;
+ b = 10;
+ #pragma omp parallel firstprivate (A::a, R::r, T<Q>::t, b)
+ {
+ int q = omp_get_thread_num ();
+ take (A::a, R::r, T<Q>::t, A::b);
+ if (a != 7 || r != 8 || T<Q>::t != 9 || b != 10)
+ __builtin_abort ();
+ A::a = 5 * q;
+ R::r = 6 * q;
+ T<Q>::t = 7 * q;
+ A::b = 8 * q;
+ take (a, r, T<Q>::t, b);
+ #pragma omp barrier
+ if (a != 5 * q || r != 6 * q || T<Q>::t != 7 * q || b != 8 * q)
+ __builtin_abort ();
+ }
+ bool f = false;
+ a = -5;
+ b = -4;
+ r = -3;
+ T<Q>::t = -2;
+ int n;
+ #pragma omp parallel for firstprivate (a, T<Q>::t, b, f) lastprivate (A::a, r, T<Q>::t, n)
+ for (int i = 0; i < omp_get_num_threads (); i++)
+ {
+ int q = omp_get_thread_num ();
+ if (!f)
+ {
+ if (A::a != -5 || A::b != -4 || T<Q>::t != -2)
+ __builtin_abort ();
+ }
+ else if (a != q || b != 2 * q || r != 3 * q || T<Q>::t != 4 * q)
+ __builtin_abort ();
+ take (a, r, T<Q>::t, b);
+ A::a = q;
+ A::b = 2 * q;
+ R::r = 3 * q;
+ T<Q>::t = 4 * q;
+ n = q;
+ f = true;
+ }
+ if (a != n || r != 3 * n || T<Q>::t != 4 * n)
+ __builtin_abort ();
+ b = 8;
+ #pragma omp parallel
+ #pragma omp single
+ for (int i = 0; i < 5; i++)
+ #pragma omp task firstprivate (T<Q>::t, b, n) private (a, R::r)
+ {
+ if (T<Q>::t != 4 * n || b != 8)
+ __builtin_abort ();
+ a = 9;
+ r = 8;
+ T<Q>::t = 12;
+ b = 18;
+ take (a, r, T<Q>::t, b);
+ if (a != 9 || r != 8 || T<Q>::t != 12 || b != 18)
+ __builtin_abort ();
+ }
+ a = 1;
+ b = 2;
+ R::r = 3;
+ T<Q>::t = 4;
+ #pragma omp parallel private (f)
+ {
+ f = false;
+ #pragma omp single
+ #pragma omp taskloop firstprivate (r, T<Q>::t, b, f) lastprivate (a, T<Q>::t, b, n)
+ for (int i = 0; i < 30; i++)
+ {
+ int q = omp_get_thread_num ();
+ if (!f)
+ {
+ if (R::r != 3 || A::b != 2 || T<Q>::t != 4)
+ __builtin_abort ();
+ }
+ else if (a != 7 * q || b != 8 * q || r != 9 * q || T<Q>::t != 10 * q)
+ __builtin_abort ();
+ take (a, r, T<Q>::t, b);
+ A::a = 7 * q;
+ A::b = 8 * q;
+ R::r = 9 * q;
+ T<Q>::t = 10 * q;
+ n = q;
+ f = true;
+ }
+ }
+ if (a != 7 * n || b != 8 * n || T<Q>::t != 10 * n)
+ __builtin_abort ();
+ a = 1;
+ b = 2;
+ R::r = 3;
+ T<Q>::t = 4;
+ #pragma omp parallel private (f)
+ {
+ f = false;
+ #pragma omp single
+ #pragma omp taskloop firstprivate (r, T<Q>::t, b, A::a, f)
+ for (int i = 0; i < 30; i++)
+ {
+ int q = omp_get_thread_num ();
+ if (!f)
+ {
+ if (A::a != 1 || R::r != 3 || A::b != 2 || T<Q>::t != 4)
+ __builtin_abort ();
+ }
+ else if (a != 7 * q || b != 8 * q || r != 9 * q || T<Q>::t != 10 * q)
+ __builtin_abort ();
+ take (a, r, T<Q>::t, b);
+ A::a = 7 * q;
+ A::b = 8 * q;
+ R::r = 9 * q;
+ T<Q>::t = 10 * q;
+ f = true;
+ }
+ }
+ #pragma omp parallel private (f)
+ {
+ f = false;
+ #pragma omp single
+ #pragma omp taskloop lastprivate (a, T<Q>::t, b, n)
+ for (int i = 0; i < 30; i++)
+ {
+ int q = omp_get_thread_num ();
+ if (f && (a != 7 * q || b != 8 * q || r != 9 * q || T<Q>::t != 10 * q))
+ __builtin_abort ();
+ take (a, r, T<Q>::t, b);
+ A::a = 7 * q;
+ A::b = 8 * q;
+ R::r = 9 * q;
+ T<Q>::t = 10 * q;
+ n = q;
+ f = true;
+ }
+ }
+ if (a != 7 * n || b != 8 * n || T<Q>::t != 10 * n)
+ __builtin_abort ();
+ #pragma omp parallel private (a, T<Q>::t, A::b, r)
+ {
+ int q = omp_get_thread_num ();
+ a = q;
+ b = 2 * q;
+ r = 3 * q;
+ T<Q>::t = 4 * q;
+ take (a, b, r, T<Q>::t);
+ #pragma omp single copyprivate (A::a, T<Q>::t, b, R::r)
+ n = q;
+ if (a != n || b != 2 * n || r != 3 * n || T<Q>::t != 4 * n)
+ __builtin_abort ();
+ }
+}
+
+int
+main ()
+{
+ A<int> a;
+ a.m1 ();
+ A<int &> b;
+ b.m1 ();
+}