Author: Akash Manna Date: 2026-10-03T18:48:21Z New Revision: 9b2ad1942cb13925325c5a8e458aac88767e2c44
URL: https://github.com/llvm/llvm-project/commit/9b2ad1942cb13925325c5a8e458aac88767e2c44 DIFF: https://github.com/llvm/llvm-project/commit/9b2ad1942cb13925325c5a8e458aac88767e2c44.diff LOG: [Clang][OpenMP] Fix crash on `copyprivate` of a data member or structured binding (#227699) Fixes #217893 `copyprivate` needs its list items to be threadprivate or private in the enclosing context. For a data member we only checked that it wasn't `shared`, and then assumed an enclosing construct had already made a private copy of it. That doesn't 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)`, where it has no attribute at all. With no copy to refer to we hit `assert(VD || isOpenMPCapturedDecl(D))`, and without assertions a null address could end up being passed to `__kmpc_copyprivate`. A structured binding in the clause hit the same assertion. A data member with no private copy is now diagnosed with the existing "copyprivate variable must be threadprivate or private in the enclosing context" error. In a dependent context the copies aren't built until instantiation, so the clause keeps the list item as written there and is checked when instantiated, like the other data-sharing clauses; that also fixes the crash for a data member in `copyprivate` inside a member function template. A structured binding stays as written too, which is how the other clauses already treat it. Added: Modified: clang/docs/ReleaseNotes.md clang/lib/Sema/SemaOpenMP.cpp clang/test/OpenMP/single_copyprivate_messages.cpp clang/test/OpenMP/structured-bindings-messages.cpp Removed: ################################################################################ diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md index d6c40a2920cf5..bf194e87f76a6 100644 --- a/clang/docs/ReleaseNotes.md +++ b/clang/docs/ReleaseNotes.md @@ -578,6 +578,9 @@ 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, 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 315f869e0b72e..efc570a8933f1 100644 --- a/clang/lib/Sema/SemaOpenMP.cpp +++ b/clang/lib/Sema/SemaOpenMP.cpp @@ -23296,11 +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) { + // A data member is private only if an enclosing construct captured it. + 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"; - reportOriginalDsa(SemaRef, DSAStack, D, DVar); + if (IsShared) + reportOriginalDsa(SemaRef, DSAStack, D, DVar); continue; } } @@ -23347,10 +23352,13 @@ OMPClause *SemaOpenMP::ActOnOpenMPCopyprivateClause(ArrayRef<Expr *> VarList, // No need to mark vars as copyprivate, they are already threadprivate or // implicitly private. - assert(VD || isOpenMPCapturedDecl(D)); + const bool IsBindingDecl = isa<BindingDecl>(D); + assert(VD || IsBindingDecl || SemaRef.CurContext->isDependentContext() || + isOpenMPCapturedDecl(D)); Vars.push_back( - VD ? RefExpr->IgnoreParens() - : buildCapture(SemaRef, D, SimpleRefExpr, /*WithInit=*/false)); + (VD || IsBindingDecl || 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 1dc508b01bd74..734c48f863b6d 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}} +} +} diff --git a/clang/test/OpenMP/structured-bindings-messages.cpp b/clang/test/OpenMP/structured-bindings-messages.cpp index 647de0055068c..88316d317ef98 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
