https://github.com/akash-manna-sky updated https://github.com/llvm/llvm-project/pull/237575
>From 349170728eb5a0bf58c663408057d2932165dafd Mon Sep 17 00:00:00 2001 From: Akash Manna <[email protected]> Date: Thu, 29 Oct 2026 21:34:17 +0530 Subject: [PATCH] Fixes #144302 A `lastprivate(i)` clause naming a data member inside a member function template of a non-template class crashed when the directive was finalized. In a dependent context the clause keeps such an item as the `this->i` member expression, since no capture can be built there yet, but `EndOpenMPDSABlock` assumed every non-dependent list item is a `DeclRefExpr` and cast it. `this->i` is not dependent when the class itself is not a template, so it got past the dependent-item check and hit the cast. Every directive that accepts `lastprivate` was affected. The finalizer now treats a member expression like a dependent item and leaves its private copy unset. The member is captured and privatized when the template is instantiated, where the clause is rebuilt in a non-dependent context and the existing code produces the copy. Diagnostics at the definition are unchanged; a const member is still rejected there. LLM tools were used for this contribution. --- clang/docs/ReleaseNotes.md | 2 + clang/lib/Sema/SemaOpenMP.cpp | 7 +++ clang/test/OpenMP/GH144302.cpp | 42 +++++++++++++ clang/test/OpenMP/sections_ast_print.cpp | 20 ++++++ .../OpenMP/sections_lastprivate_messages.cpp | 61 +++++++++++++++++++ 5 files changed, 132 insertions(+) create mode 100644 clang/test/OpenMP/GH144302.cpp diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md index e6b71ba2a0b565..8abb2737fbb98d 100644 --- a/clang/docs/ReleaseNotes.md +++ b/clang/docs/ReleaseNotes.md @@ -1388,6 +1388,8 @@ The `alpha.cplusplus.UseAfterLifetimeEnd` checker was renamed to `alpha.core.Use the clause was parsed but its condition was discarded without effect. - Fixed a crash when the loop variable or a loop bound of an OpenMP loop has a `_BitInt` type wider than any standard integer type. (#GH140074) +- Fixed a crash when a non-static data member appears in a `lastprivate` clause + inside a member function template of a non-template class. (#GH144302) - Loop-transforming constructs such as `tile` and `unroll` are now allowed inside a `simd` region for OpenMP 6.0 or later, which classifies them as simdizable. diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp index 855c2fe8f41a06..baec4a77e2fe69 100644 --- a/clang/lib/Sema/SemaOpenMP.cpp +++ b/clang/lib/Sema/SemaOpenMP.cpp @@ -3021,6 +3021,13 @@ void SemaOpenMP::EndOpenMPDSABlock(Stmt *CurDirective) { PrivateCopies.push_back(nullptr); continue; } + // Data members are captured, and get private copies, on instantiation. + if (isa<MemberExpr>(DE->IgnoreParens())) { + assert(SemaRef.CurContext->isDependentContext() && + "uncaptured data member in a non-dependent context"); + PrivateCopies.push_back(nullptr); + continue; + } auto *DRE = cast<DeclRefExpr>(DE->IgnoreParens()); auto *D = DRE->getDecl(); if (auto *BD = dyn_cast<BindingDecl>(D)) { diff --git a/clang/test/OpenMP/GH144302.cpp b/clang/test/OpenMP/GH144302.cpp new file mode 100644 index 00000000000000..d3200541007d75 --- /dev/null +++ b/clang/test/OpenMP/GH144302.cpp @@ -0,0 +1,42 @@ +// RUN: %clang_cc1 -verify -fopenmp -fsyntax-only %s +// RUN: %clang_cc1 -verify -fopenmp-simd -fsyntax-only %s +// RUN: %clang_cc1 -verify -fopenmp -triple x86_64-unknown-linux-gnu -emit-llvm %s -o - | FileCheck %s +// expected-no-diagnostics + +// The data member is not captured until the template is instantiated. +struct B +{ + int i; + template<typename T> +void foo(); +}; + +template<typename T> +void B::foo() +{ +#pragma omp parallel + { + #pragma omp sections lastprivate (i) + { + i = 0; + } + } +} + +template void B::foo<int>(); + +int main() { + B b; + b.foo<int>(); + return b.i; +} + +// CHECK-LABEL: define {{.*}}void @_ZN1B3fooIiEEvv( +// CHECK: call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr @{{.+}}, i32 1, ptr @[[OUTLINED:_ZN1B3fooIiEEvv.omp_outlined]], ptr %{{.+}}) + +// CHECK: define internal void @[[OUTLINED]]( +// CHECK: call void @__kmpc_for_static_init_4( +// CHECK: call void @__kmpc_for_static_fini( +// CHECK: .omp.lastprivate.then: +// CHECK: .omp.lastprivate.done: +// CHECK: call void @__kmpc_barrier( diff --git a/clang/test/OpenMP/sections_ast_print.cpp b/clang/test/OpenMP/sections_ast_print.cpp index 26bd47685ea7c2..84eb60f2e0b99f 100644 --- a/clang/test/OpenMP/sections_ast_print.cpp +++ b/clang/test/OpenMP/sections_ast_print.cpp @@ -30,6 +30,26 @@ T tmain(T argc) { return T(); } +struct S { + int a; + template <class T> void foo(); +}; + +template <class T> void S::foo() { +#pragma omp parallel +#pragma omp sections firstprivate(a) lastprivate(this->a) + { + a = 0; + } +} +// CHECK: template <class T> void S::foo() { +// CHECK-NEXT: #pragma omp parallel +// CHECK-NEXT: #pragma omp sections firstprivate(this->a) lastprivate(this->a){{$}} +// CHECK-NEXT: { +// CHECK-NEXT: this->a = 0; +// CHECK-NEXT: } +// CHECK-NEXT: } + int main(int argc, char **argv) { // CHECK: int main(int argc, char **argv) { int b = argc, c, d, e, f, g; diff --git a/clang/test/OpenMP/sections_lastprivate_messages.cpp b/clang/test/OpenMP/sections_lastprivate_messages.cpp index c182b4e71ae9ea..2898486b9a91a1 100644 --- a/clang/test/OpenMP/sections_lastprivate_messages.cpp +++ b/clang/test/OpenMP/sections_lastprivate_messages.cpp @@ -66,6 +66,67 @@ class S6 { S3 h; #pragma omp threadprivate(h) // expected-note 2 {{defined as threadprivate or thread local}} +// GH144302: data members in a member template of a non-template class. +struct GH144302 { + int i; + const int c = 0; // expected-note {{'c' declared here}} + template <typename T> void foo(); + template <typename T> void bar() { +#pragma omp parallel +#pragma omp sections lastprivate(c) // expected-error {{const-qualified variable cannot be lastprivate}} + { + foo<T>(); + } + } +}; +template <class U> struct GH144302T { + int i; + template <typename T> void foo() { +#pragma omp parallel +#pragma omp sections lastprivate(i) + { + i = 0; + } + } +}; +int GH144302g; +template <typename T> void GH144302::foo() { + int x = 0; +#pragma omp parallel + { +#pragma omp sections lastprivate(i) + { + i = 0; + } + } +#pragma omp parallel +#pragma omp sections lastprivate(this->i) + { + i = 0; + } +#pragma omp parallel +#pragma omp sections firstprivate(i) lastprivate(i) + { + i = 0; + } +#pragma omp parallel for lastprivate(i) + for (int k = 0; k < 10; ++k) + i = k; +#pragma omp parallel +#pragma omp sections private(i) + { + i = 0; + } +#pragma omp parallel +#pragma omp sections lastprivate(x, GH144302g) + { + x = GH144302g = 0; + } + GH144302T<int> t; + t.foo<T>(); +} +template void GH144302::foo<int>(); + template <class I, class C> int foomain(int argc, char **argv) { I e(4); _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
