Skip to content

Commit dce4c6a

Browse files
authored
[SYCL] Enable diagnosing of indirect implicit capture of "this" (#4745)
The compiler issues an error if a lambda passed directly to a SYCL kernel function implicitly captures "this", but does not issue an error if the lambda that captures "this" is itself captured by the kernel lambda. The situation when SYCL kernel function captures lambda is a normal workflow for SYCL reductions, so it is important to diagnose this case as well.
1 parent 7dcb404 commit dce4c6a

File tree

2 files changed

+88
-9
lines changed

2 files changed

+88
-9
lines changed

clang/lib/Sema/SemaSYCL.cpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1703,6 +1703,15 @@ class SyclKernelFieldChecker : public SyclKernelFieldHandler {
17031703

17041704
bool handleStructType(FieldDecl *FD, QualType FieldTy) final {
17051705
IsInvalid |= checkNotCopyableToKernel(FD, FieldTy);
1706+
CXXRecordDecl *RD = FieldTy->getAsCXXRecordDecl();
1707+
assert(RD && "Not a RecordDecl inside the handler for struct type");
1708+
if (RD->isLambda()) {
1709+
for (const LambdaCapture &LC : RD->captures())
1710+
if (LC.capturesThis() && LC.isImplicit()) {
1711+
SemaRef.Diag(LC.getLocation(), diag::err_implicit_this_capture);
1712+
IsInvalid = true;
1713+
}
1714+
}
17061715
return isValid();
17071716
}
17081717

@@ -3758,7 +3767,6 @@ void Sema::CheckSYCLKernelCall(FunctionDecl *KernelFunc, SourceRange CallLoc,
37583767
for (const LambdaCapture &LC : KernelObj->captures())
37593768
if (LC.capturesThis() && LC.isImplicit()) {
37603769
Diag(LC.getLocation(), diag::err_implicit_this_capture);
3761-
Diag(CallLoc.getBegin(), diag::note_used_here);
37623770
KernelFunc->setInvalidDecl();
37633771
}
37643772
}

clang/test/SemaSYCL/lambda_implicit_capture_this.cpp

Lines changed: 79 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,95 @@
11
// RUN: %clang_cc1 -fsycl-is-device -fsyntax-only -Wno-sycl-2017-compat -verify %s
2+
//
3+
// This test checks that the compiler issues an error on attempt to capture
4+
// "this" pointer by lambdas passed to the device code (directly and indirectly)
25

3-
template <typename name, typename Func>
4-
__attribute__((sycl_kernel)) void kernel(const Func &kernelFunc) {
5-
kernelFunc();
6-
}
6+
#include "Inputs/sycl.hpp"
7+
using namespace cl::sycl;
8+
queue q;
79

810
class Class {
911
public:
1012
Class() : member(1) {}
1113
void function();
14+
void function2();
15+
void function3();
1216
int member;
1317
};
1418

19+
void Class::function3() {
20+
auto Lambda = [=]() {
21+
int acc[1] = {5};
22+
acc[0] *= member;
23+
};
24+
}
25+
26+
void Class::function2() {
27+
auto Lambda = [=]() {
28+
int acc[1] = {5};
29+
acc[0] *= member;
30+
};
31+
function3();
32+
}
33+
1534
void Class::function() {
16-
// expected-note@+1{{used here}}
17-
kernel<class kernel_wrapper>(
18-
[=]() {
35+
auto Lambda = [=]() {
36+
int acc[1] = {5};
37+
acc[0] *= member; // expected-error 2{{implicit capture of 'this' is not allowed for kernel functions}}
38+
};
39+
q.submit([&](handler &h) {
40+
// expected-note@+1 {{in instantiation of function template specialization}}
41+
h.single_task<class Simple>([=]() {
42+
int acc[1] = {5};
43+
acc[0] *= member; // expected-error{{implicit capture of 'this' is not allowed for kernel functions}}
44+
});
45+
});
46+
q.submit([&](handler &h) {
47+
// expected-note@+1 {{in instantiation of function template specialization}}
48+
h.single_task<class CapturedOnDevice>([=]() {
49+
auto DeviceLambda = [=]() {
1950
int acc[1] = {5};
2051
acc[0] *= member; // expected-error{{implicit capture of 'this' is not allowed for kernel functions}}
21-
});
52+
};
53+
DeviceLambda();
54+
});
55+
});
56+
q.submit([&](handler &h) {
57+
// expected-note@+1 {{in instantiation of function template specialization}}
58+
h.single_task<class CapturedOnDevice1>([=]() {
59+
// FIXME: That is probably not correct source location for a diagnostic
60+
function2(); // expected-error{{implicit capture of 'this' is not allowed for kernel functions}}
61+
});
62+
});
63+
q.submit([&](handler &h) {
64+
// expected-note@+1 {{in instantiation of function template specialization}}
65+
h.single_task<class CapturedOnDevice2>([=]() {
66+
// FIXME: That is probably not correct source location for a diagnostic
67+
function3(); // expected-error{{implicit capture of 'this' is not allowed for kernel functions}}
68+
});
69+
});
70+
q.submit([&](handler &h) {
71+
// expected-note@+1 {{in instantiation of function template specialization}}
72+
h.single_task<class CapturedOnHost>([=]() {
73+
Lambda();
74+
});
75+
});
76+
q.submit([&](handler &h) {
77+
// expected-note@+1 {{in instantiation of function template specialization}}
78+
h.single_task<class CapturedOnHost1>([Lambda]() {
79+
});
80+
});
81+
auto InnerLambda = [=]() {
82+
int A = 2 + member; // expected-error {{implicit capture of 'this' is not allowed for kernel functions}}
83+
};
84+
auto ExternalLambda = [=]() {
85+
InnerLambda();
86+
};
87+
q.submit([&](handler &h) {
88+
// expected-note@+1 {{in instantiation of function template specialization}}
89+
h.single_task<class CapturedOnHost2>([=]() {
90+
ExternalLambda();
91+
});
92+
});
2293
}
2394

2495
int main(int argc, char *argv[]) {

0 commit comments

Comments
 (0)