@@ -5829,7 +5829,7 @@ omp_is_private (struct gimplify_omp_ctx
region's REDUCTION clause. */
static bool
-omp_check_private (struct gimplify_omp_ctx *ctx, tree decl)
+omp_check_private (struct gimplify_omp_ctx *ctx, tree decl, bool copyprivate)
{
splay_tree_node n;
@@ -5838,8 +5838,11 @@ 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. */
- || lang_hooks.decls.omp_privatize_by_reference (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 ((ctx->region_type & (ORT_TARGET | ORT_TARGET_DATA)) != 0)
continue;
@@ -6049,12 +6052,36 @@ gimplify_scan_omp_clauses (tree *list_p,
remove = true;
break;
}
+ if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_COPYPRIVATE
+ && !remove
+ && !omp_check_private (ctx, decl, true))
+ {
+ remove = true;
+ if (is_global_var (decl))
+ {
+ if (DECL_THREAD_LOCAL_P (decl))
+ remove = false;
+ else if (DECL_HAS_VALUE_EXPR_P (decl))
+ {
+ tree value = get_base_address (DECL_VALUE_EXPR (decl));
+
+ if (value
+ && DECL_P (value)
+ && DECL_THREAD_LOCAL_P (value))
+ remove = false;
+ }
+ }
+ if (remove)
+ error_at (OMP_CLAUSE_LOCATION (c),
+ "copyprivate variable %qE is not threadprivate"
+ " or private in outer context", DECL_NAME (decl));
+ }
do_notice:
if (outer_ctx)
omp_notice_variable (outer_ctx, decl, true);
if (check_non_private
&& region_type == ORT_WORKSHARE
- && omp_check_private (ctx, decl))
+ && omp_check_private (ctx, decl, false))
{
error ("%s variable %qE is private in outer context",
check_non_private, DECL_NAME (decl));
@@ -0,0 +1,24 @@
+! PR libgomp/59467
+! { dg-do compile }
+! { dg-options "-fopenmp" }
+ FUNCTION t()
+ INTEGER :: a, b, t
+ a = 0
+ b = 0
+ !$OMP PARALLEL REDUCTION(+:b)
+ !$OMP SINGLE ! { dg-error "is not threadprivate or private in outer context" }
+ !$OMP ATOMIC WRITE
+ a = 6
+ !$OMP END SINGLE COPYPRIVATE (a)
+ b = a
+ !$OMP END PARALLEL
+ t = b
+ b = 0
+ !$OMP PARALLEL REDUCTION(+:b)
+ !$OMP SINGLE
+ !$OMP ATOMIC WRITE
+ b = 6
+ !$OMP END SINGLE COPYPRIVATE (b)
+ !$OMP END PARALLEL
+ t = t + b
+ END FUNCTION
@@ -0,0 +1,68 @@
+/* PR libgomp/59467 */
+
+int v;
+
+void
+foo (void)
+{
+ int x = 0, y = 0;
+ #pragma omp parallel
+ {
+ int z;
+ #pragma omp single copyprivate (x) /* { dg-error "is not threadprivate or private in outer context" } */
+ {
+ #pragma omp atomic write
+ x = 6;
+ }
+ #pragma omp atomic read
+ z = x;
+ #pragma omp atomic
+ y += z;
+ }
+ #pragma omp parallel
+ {
+ int z;
+ #pragma omp single copyprivate (v) /* { dg-error "is not threadprivate or private in outer context" } */
+ {
+ #pragma omp atomic write
+ v = 6;
+ }
+ #pragma omp atomic read
+ z = v;
+ #pragma omp atomic
+ y += z;
+ }
+ #pragma omp parallel private (x)
+ {
+ int z;
+ #pragma omp single copyprivate (x)
+ {
+ #pragma omp atomic write
+ x = 6;
+ }
+ #pragma omp atomic read
+ z = x;
+ #pragma omp atomic
+ y += z;
+ }
+ x = 0;
+ #pragma omp parallel reduction (+:x)
+ {
+ #pragma omp single copyprivate (x)
+ {
+ #pragma omp atomic write
+ x = 6;
+ }
+ #pragma omp atomic
+ y += x;
+ }
+ #pragma omp single copyprivate (x)
+ {
+ x = 7;
+ }
+ #pragma omp single copyprivate (v) /* { dg-error "is not threadprivate or private in outer context" } */
+ {
+ #pragma omp atomic write
+ v = 6;
+ }
+}
@@ -12,7 +12,7 @@
b = 2
c = 3
l = .false.
-!$omp parallel num_threads (3) reduction (.or.:l)
+!$omp parallel num_threads (3) reduction (.or.:l) private (d)
if (omp_get_thread_num () .eq. 0) then
ip = loc (a)
elseif (omp_get_thread_num () .eq. 1) then