diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -15326,6 +15326,15 @@ return true; } + if (getLangOpts().OpenMP && getLangOpts().OpenMPUseTLS) { + // Avoid capturing TLS-backed threadprivate variables in outer scopes. + if (VarDC->Equals(ParentDC) && Var->hasAttr() && + IsGlobal) { + FunctionScopesIndex = MaxFunctionScopesIndex - 1; + break; + } + } + FunctionScopeInfo *FSI = FunctionScopes[FunctionScopesIndex]; CapturingScopeInfo *CSI = cast(FSI); diff --git a/clang/test/OpenMP/nested_parallel_threadprivate_copyin.cpp b/clang/test/OpenMP/nested_parallel_threadprivate_copyin.cpp new file mode 100644 --- /dev/null +++ b/clang/test/OpenMP/nested_parallel_threadprivate_copyin.cpp @@ -0,0 +1,48 @@ +// RUN: %clang_cc1 %s -fopenmp -emit-llvm -o - | FileCheck %s +#define NT 4 /* default number of threads */ + +extern "C" { +extern int printf(const char *, ...); +extern void assert(int); +extern void omp_set_dynamic(bool); +extern void omp_set_num_threads(int); +extern void omp_set_nested(bool); +extern int omp_get_thread_num(void); +extern int omp_get_ancestor_thread_num(int); +}; + +int main(void) { + static int threadprivate_var = 1; + #pragma omp threadprivate(threadprivate_var) + + // These commands are not strictly necessary, but they make it easier to + // see when things go wrong. + omp_set_dynamic(false); + omp_set_num_threads(NT); + omp_set_nested(true); + + // CHECK-NOT: call void.*@__kmpc_fork_call({{.*}}%{{\w+}}threadprivate{{.*}}) + // CHECK-NOT: define internal void @.omp_outlined.({{.*}}%threadprivate_var{{.*}}) + #pragma omp parallel + { + threadprivate_var = 1; + printf("[B] thread %d: val %d: threadprivate @ %p\n", omp_get_thread_num(), threadprivate_var, &threadprivate_var); + + #pragma omp master + { + threadprivate_var = 2; + // CHECK: define internal void @.omp_outlined..2({{.*}}%threadprivate_var{{.*}}) + #pragma omp parallel copyin(threadprivate_var) + { + printf("[B] thread %d, %d: val %d: threadprivate @ %p\n", omp_get_ancestor_thread_num(1), omp_get_thread_num(), threadprivate_var, &threadprivate_var); + // check that copyin succeeded + assert(threadprivate_var == 2); + } + } + #pragma omp barrier + printf("[A] thread %d: val %d: threadprivate @ %p\n", omp_get_thread_num(), threadprivate_var, &threadprivate_var); + if (omp_get_thread_num() != 0) // 0 is the master thread + // non-master threads should not have seen changes + assert(threadprivate_var == 1); + } +}