https://github.com/akash-manna-sky updated https://github.com/llvm/llvm-project/pull/227699
>From be5882a227116e5ea3014aeeb47364bf89b251cf Mon Sep 17 00:00:00 2001 From: Akash Manna <[email protected]> Date: Wed, 30 Sep 2026 18:38:26 +0530 Subject: [PATCH 1/2] [Clang][OpenMP] Fix crash on `copyprivate` of a non-privatized data member `copyprivate` needs its list items to be threadprivate or private in the enclosing context. For a data member we only checked that it was not `shared` and then assumed an enclosing construct had already made a private copy of it. That does not hold in a `task` or `taskloop` region, where a member that is private outside is implicitly firstprivate but gets no copy, or under `default(none)`. With no copy to refer to we hit `assert(VD || isOpenMPCapturedDecl(D))`. Diagnose such a member with the existing "copyprivate variable must be threadprivate or private in the enclosing context" error. In a dependent context the copies are not built until instantiation, so keep the list item as written there and check it on instantiation, like the other data-sharing clauses do. Fixes #217893 --- clang/docs/ReleaseNotes.md | 2 + clang/lib/Sema/SemaOpenMP.cpp | 16 ++++++-- .../OpenMP/single_copyprivate_messages.cpp | 41 +++++++++++++++++++ 3 files changed, 56 insertions(+), 3 deletions(-) diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md index 6afaa6675be7cd..b55502e2003455 100644 --- a/clang/docs/ReleaseNotes.md +++ b/clang/docs/ReleaseNotes.md @@ -572,6 +572,8 @@ features cannot lower the translation-unit ABI level; - Fixed a bug where a stray closing curley brace in an OpenMP/OpenACC pragma could cause pragma parsing issues when inside of a member function. (#GH214195) - Fixed a bug where preprocessor directives following comments were not correctly recognized when using -C. (#GH48361) - Fixed a crash when declaring a member template within a local class inside an OpenMP region. (#GH216052) +- Fixed a crash when an OpenMP `copyprivate` clause names a non-static data member that is not private in the + enclosing context, which is now diagnosed, or names a data member inside a member function template. (#GH217893) - Fixed an assertion failure when a variable implicitly mapped by an OpenMP `target` directive has a class type (such as `std::map`) whose mapper lookup instantiates a class template specialization. (#GH154704) - Fixed a bug where repeated #imports of modular headers in non-modular compilation were translated to #pragma clang module import. (#GH216924) diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp index 6ef86b8391f40c..2fb49c14b3aa51 100644 --- a/clang/lib/Sema/SemaOpenMP.cpp +++ b/clang/lib/Sema/SemaOpenMP.cpp @@ -23303,6 +23303,14 @@ OMPClause *SemaOpenMP::ActOnOpenMPCopyprivateClause(ArrayRef<Expr *> VarList, reportOriginalDsa(SemaRef, DSAStack, D, DVar); continue; } + // A data member is private only if an enclosing construct captured it. + if (isa<FieldDecl>(D) && !SemaRef.CurContext->isDependentContext() && + !isOpenMPCapturedDecl(D)) { + Diag(ELoc, diag::err_omp_required_access) + << getOpenMPClauseNameForDiag(OMPC_copyprivate) + << "threadprivate or private in the enclosing context"; + continue; + } } } @@ -23347,10 +23355,12 @@ OMPClause *SemaOpenMP::ActOnOpenMPCopyprivateClause(ArrayRef<Expr *> VarList, // No need to mark vars as copyprivate, they are already threadprivate or // implicitly private. - assert(VD || isOpenMPCapturedDecl(D)); + assert(VD || SemaRef.CurContext->isDependentContext() || + isOpenMPCapturedDecl(D)); Vars.push_back( - VD ? RefExpr->IgnoreParens() - : buildCapture(SemaRef, D, SimpleRefExpr, /*WithInit=*/false)); + (VD || SemaRef.CurContext->isDependentContext()) + ? RefExpr->IgnoreParens() + : buildCapture(SemaRef, D, SimpleRefExpr, /*WithInit=*/false)); SrcExprs.push_back(PseudoSrcExpr); DstExprs.push_back(PseudoDstExpr); AssignmentOps.push_back(AssignmentOp.get()); diff --git a/clang/test/OpenMP/single_copyprivate_messages.cpp b/clang/test/OpenMP/single_copyprivate_messages.cpp index 1dc508b01bd74b..734c48f863b6dd 100644 --- a/clang/test/OpenMP/single_copyprivate_messages.cpp +++ b/clang/test/OpenMP/single_copyprivate_messages.cpp @@ -206,3 +206,44 @@ int parallel() { return 0; } + +namespace GH217893 { +struct S { + int a; + S() { +#pragma omp parallel firstprivate(a) +#pragma omp taskloop +#pragma omp single copyprivate(a) // expected-error {{copyprivate variable must be threadprivate or private in the enclosing context}} expected-error {{region cannot be closely nested inside 'taskloop' region; perhaps you forget to enclose 'omp single' directive into a parallel region?}} + }; // expected-error {{expected statement}} + + void nested() { +#pragma omp parallel firstprivate(a) +#pragma omp taskloop + for (int i = 0; i < 2; ++i) { +#pragma omp single copyprivate(a) // expected-error {{copyprivate variable must be threadprivate or private in the enclosing context}} expected-error {{region cannot be closely nested inside 'taskloop' region; perhaps you forget to enclose 'omp single' directive into a parallel region?}} + foo(); + } +#pragma omp parallel default(none) +#pragma omp single copyprivate(a) // expected-error {{copyprivate variable must be threadprivate or private in the enclosing context}} + foo(); +#pragma omp parallel private(a) +#pragma omp single copyprivate(a) + foo(); + } + + template <class T> void dependent() { +#pragma omp parallel private(a) +#pragma omp single copyprivate(a) + foo(); +#pragma omp parallel private(a) +#pragma omp task +#pragma omp taskgroup +#pragma omp single copyprivate(a) // expected-error {{copyprivate variable must be threadprivate or private in the enclosing context}} + foo(); + } +}; + +void instantiate(S &s) { + s.dependent<int>(); // expected-note {{in instantiation of function template specialization 'GH217893::S::dependent<int>' requested here}} +} +} >From bbe0178523c39dd86215613cf0cee4c674f01449 Mon Sep 17 00:00:00 2001 From: Akash Manna <[email protected]> Date: Sat, 3 Oct 2026 09:45:21 +0530 Subject: [PATCH 2/2] [Clang][OpenMP] Keep structured bindings as written in copyprivate Review follow-up for #227699. A structured binding in `copyprivate` hit the same assertion; it now stays as written in the clause, like the other data-sharing clauses treat it. The data-member check is folded into the `shared` branch and the DSA note is only reported for the `shared` case. --- clang/docs/ReleaseNotes.md | 3 +- clang/lib/Sema/SemaOpenMP.cpp | 20 ++++----- .../OpenMP/structured-bindings-messages.cpp | 42 +++++++++++++++++++ 3 files changed, 53 insertions(+), 12 deletions(-) diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md index b55502e2003455..4a00a5b7b76669 100644 --- a/clang/docs/ReleaseNotes.md +++ b/clang/docs/ReleaseNotes.md @@ -573,7 +573,8 @@ features cannot lower the translation-unit ABI level; - Fixed a bug where preprocessor directives following comments were not correctly recognized when using -C. (#GH48361) - Fixed a crash when declaring a member template within a local class inside an OpenMP region. (#GH216052) - Fixed a crash when an OpenMP `copyprivate` clause names a non-static data member that is not private in the - enclosing context, which is now diagnosed, or names a data member inside a member function template. (#GH217893) + enclosing context, which is now diagnosed, a data member inside a member function template, or a structured + binding. (#GH217893) - Fixed an assertion failure when a variable implicitly mapped by an OpenMP `target` directive has a class type (such as `std::map`) whose mapper lookup instantiates a class template specialization. (#GH154704) - Fixed a bug where repeated #imports of modular headers in non-modular compilation were translated to #pragma clang module import. (#GH216924) diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp index 2fb49c14b3aa51..aa8f13ebb3b789 100644 --- a/clang/lib/Sema/SemaOpenMP.cpp +++ b/clang/lib/Sema/SemaOpenMP.cpp @@ -23296,19 +23296,16 @@ OMPClause *SemaOpenMP::ActOnOpenMPCopyprivateClause(ArrayRef<Expr *> VarList, // threadprivate or private in the enclosing context. if (DVar.CKind == OMPC_unknown) { DVar = DSAStack->getImplicitDSA(D, false); - if (DVar.CKind == OMPC_shared) { - Diag(ELoc, diag::err_omp_required_access) - << getOpenMPClauseNameForDiag(OMPC_copyprivate) - << "threadprivate or private in the enclosing context"; - reportOriginalDsa(SemaRef, DSAStack, D, DVar); - continue; - } // A data member is private only if an enclosing construct captured it. - if (isa<FieldDecl>(D) && !SemaRef.CurContext->isDependentContext() && - !isOpenMPCapturedDecl(D)) { + const bool IsShared = DVar.CKind == OMPC_shared; + if (IsShared || + (isa<FieldDecl>(D) && !SemaRef.CurContext->isDependentContext() && + !isOpenMPCapturedDecl(D))) { Diag(ELoc, diag::err_omp_required_access) << getOpenMPClauseNameForDiag(OMPC_copyprivate) << "threadprivate or private in the enclosing context"; + if (IsShared) + reportOriginalDsa(SemaRef, DSAStack, D, DVar); continue; } } @@ -23355,10 +23352,11 @@ OMPClause *SemaOpenMP::ActOnOpenMPCopyprivateClause(ArrayRef<Expr *> VarList, // No need to mark vars as copyprivate, they are already threadprivate or // implicitly private. - assert(VD || SemaRef.CurContext->isDependentContext() || + const bool IsBindingDecl = isa<BindingDecl>(D); + assert(VD || IsBindingDecl || SemaRef.CurContext->isDependentContext() || isOpenMPCapturedDecl(D)); Vars.push_back( - (VD || SemaRef.CurContext->isDependentContext()) + (VD || IsBindingDecl || SemaRef.CurContext->isDependentContext()) ? RefExpr->IgnoreParens() : buildCapture(SemaRef, D, SimpleRefExpr, /*WithInit=*/false)); SrcExprs.push_back(PseudoSrcExpr); diff --git a/clang/test/OpenMP/structured-bindings-messages.cpp b/clang/test/OpenMP/structured-bindings-messages.cpp index 647de0055068cd..88316d317ef981 100644 --- a/clang/test/OpenMP/structured-bindings-messages.cpp +++ b/clang/test/OpenMP/structured-bindings-messages.cpp @@ -563,3 +563,45 @@ void test_bindings_only_orig_not_dereferenced() { c = c + 30; } } + +void test_copyprivate_orphaned() { + Point p{1, 2}; + auto [a, b] = p; +#pragma omp single copyprivate(a, b) + ; +} + +void test_copyprivate_private() { + Point p{1, 2}; + auto [a, b] = p; +#pragma omp parallel private(a, b) +#pragma omp single copyprivate(a, b) + ; +} + +void test_copyprivate_firstprivate() { + Point p{1, 2}; + auto [a, b] = p; +#pragma omp parallel firstprivate(a) +#pragma omp single copyprivate(a) + ; +} + +void test_copyprivate_shared() { + Point p{1, 2}; + auto [a, b] = p; +#pragma omp parallel // expected-note {{implicitly determined as shared}} +#pragma omp single copyprivate(a) // expected-error {{copyprivate variable must be threadprivate or private in the enclosing context}} + ; +} + +template <typename T> void test_copyprivate_template(T p) { + auto [a, b] = p; +#pragma omp parallel private(a) +#pragma omp single copyprivate(a) + ; +} + +void instantiate_copyprivate_template() { + test_copyprivate_template(Point{1, 2}); +} _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
