Skip to content

Commit c767edc

Browse files
author
Erich Keane
authored
[SYCL] Move kernel diagnostics to the cal and, enable template trail on errors (#2289)
This patch moves the diagnostics for the kernel to the point in which the kernel is called, rather than when generating the kernel. This means that the call location is available (so that the checkers can be taught how to print better diagnostics in the future). The biggest impact of this, is that it causes us to print the template instantiation 'tree' since these are diagnosing right away. Currently, this uses the call location to better diagnose the lambda check (see the additional note there!), and prints a kernel-parameter-must-be-lambda-or-functor error.
1 parent ba215c0 commit c767edc

File tree

6 files changed

+77
-25
lines changed

6 files changed

+77
-25
lines changed

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10948,6 +10948,8 @@ def err_sycl_kernel_incorrectly_named : Error<
1094810948
"|needs to have a globally-visible name"
1094910949
"|name is invalid. Unscoped enum requires fixed underlying type"
1095010950
"}0">;
10951+
def err_sycl_kernel_not_function_object
10952+
: Error<"kernel parameter must be a lambda or function object">;
1095110953
def err_sycl_restrict : Error<
1095210954
"SYCL kernel cannot "
1095310955
"%select{use a non-const global variable"

clang/include/clang/Sema/Sema.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12306,6 +12306,9 @@ class Sema final {
1230612306
bool IsMemberFunction, SourceLocation Loc, SourceRange Range,
1230712307
VariadicCallType CallType);
1230812308

12309+
void CheckSYCLKernelCall(FunctionDecl *CallerFunc, SourceRange CallLoc,
12310+
ArrayRef<const Expr *> Args);
12311+
1230912312
bool CheckObjCString(Expr *Arg);
1231012313
ExprResult CheckOSLogFormatStringArg(Expr *Arg);
1231112314

@@ -12727,7 +12730,7 @@ class Sema final {
1272712730
// Used to suppress diagnostics during kernel construction, since these were
1272812731
// already emitted earlier. Diagnosing during Kernel emissions also skips the
1272912732
// useful notes that shows where the kernel was called.
12730-
bool ConstructingOpenCLKernel = false;
12733+
bool DiagnosingSYCLKernel = false;
1273112734

1273212735
public:
1273312736
void addSyclDeviceDecl(Decl *d) { SyclDeviceDecls.insert(d); }

clang/lib/Sema/SemaChecking.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4558,6 +4558,9 @@ void Sema::checkCall(NamedDecl *FDecl, const FunctionProtoType *Proto,
45584558
if (FD)
45594559
diagnoseArgDependentDiagnoseIfAttrs(FD, ThisArg, Args, Loc);
45604560

4561+
if (FD && FD->hasAttr<SYCLKernelAttr>())
4562+
CheckSYCLKernelCall(FD, Range, Args);
4563+
45614564
// Diagnose variadic calls in SYCL.
45624565
if (FD && FD ->isVariadic() && getLangOpts().SYCLIsDevice &&
45634566
!isUnevaluatedContext() && !isKnownGoodSYCLDecl(FD))

clang/lib/Sema/SemaSYCL.cpp

Lines changed: 42 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -706,7 +706,8 @@ getKernelInvocationKind(FunctionDecl *KernelCallerFunc) {
706706
}
707707

708708
static const CXXRecordDecl *getKernelObjectType(FunctionDecl *Caller) {
709-
return (*Caller->param_begin())->getType()->getAsCXXRecordDecl();
709+
assert(Caller->getNumParams() > 0 && "Insufficient kernel parameters");
710+
return Caller->getParamDecl(0)->getType()->getAsCXXRecordDecl();
710711
}
711712

712713
/// Creates a kernel parameter descriptor
@@ -1205,7 +1206,6 @@ class SyclKernelFieldChecker : public SyclKernelFieldHandler {
12051206
class SyclKernelDeclCreator : public SyclKernelFieldHandler {
12061207
FunctionDecl *KernelDecl;
12071208
llvm::SmallVector<ParmVarDecl *, 8> Params;
1208-
SyclKernelFieldChecker &ArgChecker;
12091209
Sema::ContextRAII FuncContext;
12101210
// Holds the last handled field's first parameter. This doesn't store an
12111211
// iterator as push_back invalidates iterators.
@@ -1339,13 +1339,12 @@ class SyclKernelDeclCreator : public SyclKernelFieldHandler {
13391339
}
13401340

13411341
public:
1342-
SyclKernelDeclCreator(Sema &S, SyclKernelFieldChecker &ArgChecker,
1343-
StringRef Name, SourceLocation Loc, bool IsInline,
1344-
bool IsSIMDKernel)
1342+
SyclKernelDeclCreator(Sema &S, StringRef Name, SourceLocation Loc,
1343+
bool IsInline, bool IsSIMDKernel)
13451344
: SyclKernelFieldHandler(S),
13461345
KernelDecl(createKernelDecl(S.getASTContext(), Name, Loc, IsInline,
13471346
IsSIMDKernel)),
1348-
ArgChecker(ArgChecker), FuncContext(SemaRef, KernelDecl) {}
1347+
FuncContext(SemaRef, KernelDecl) {}
13491348

13501349
~SyclKernelDeclCreator() {
13511350
ASTContext &Ctx = SemaRef.getASTContext();
@@ -1360,8 +1359,7 @@ class SyclKernelDeclCreator : public SyclKernelFieldHandler {
13601359
KernelDecl->setType(FuncType);
13611360
KernelDecl->setParams(Params);
13621361

1363-
if (ArgChecker.isValid())
1364-
SemaRef.addSyclDeviceDecl(KernelDecl);
1362+
SemaRef.addSyclDeviceDecl(KernelDecl);
13651363
}
13661364

13671365
bool handleSyclAccessorType(const CXXBaseSpecifier &BS,
@@ -2015,8 +2013,38 @@ class SyclKernelIntHeaderCreator : public SyclKernelFieldHandler {
20152013
using SyclKernelFieldHandler::handleSyclHalfType;
20162014
using SyclKernelFieldHandler::handleSyclSamplerType;
20172015
};
2016+
20182017
} // namespace
20192018

2019+
void Sema::CheckSYCLKernelCall(FunctionDecl *KernelFunc, SourceRange CallLoc,
2020+
ArrayRef<const Expr *> Args) {
2021+
const CXXRecordDecl *KernelObj = getKernelObjectType(KernelFunc);
2022+
if (!KernelObj) {
2023+
Diag(Args[0]->getExprLoc(), diag::err_sycl_kernel_not_function_object);
2024+
KernelFunc->setInvalidDecl();
2025+
return;
2026+
}
2027+
2028+
if (KernelObj->isLambda()) {
2029+
for (const LambdaCapture &LC : KernelObj->captures())
2030+
if (LC.capturesThis() && LC.isImplicit()) {
2031+
Diag(LC.getLocation(), diag::err_implicit_this_capture);
2032+
Diag(CallLoc.getBegin(), diag::note_used_here);
2033+
KernelFunc->setInvalidDecl();
2034+
}
2035+
}
2036+
2037+
SyclKernelFieldChecker Checker(*this);
2038+
2039+
KernelObjVisitor Visitor{*this};
2040+
DiagnosingSYCLKernel = true;
2041+
Visitor.VisitRecordBases(KernelObj, Checker);
2042+
Visitor.VisitRecordFields(KernelObj, Checker);
2043+
DiagnosingSYCLKernel = false;
2044+
if (!Checker.isValid())
2045+
KernelFunc->setInvalidDecl();
2046+
}
2047+
20202048
// Generates the OpenCL kernel using KernelCallerFunc (kernel caller
20212049
// function) defined is SYCL headers.
20222050
// Generated OpenCL kernel contains the body of the kernel caller function,
@@ -2051,29 +2079,19 @@ void Sema::ConstructOpenCLKernel(FunctionDecl *KernelCallerFunc,
20512079
constructKernelName(*this, KernelCallerFunc, MC);
20522080
StringRef KernelName(getLangOpts().SYCLUnnamedLambda ? StableName
20532081
: CalculatedName);
2054-
if (KernelObj->isLambda()) {
2055-
for (const LambdaCapture &LC : KernelObj->captures())
2056-
if (LC.capturesThis() && LC.isImplicit())
2057-
Diag(LC.getLocation(), diag::err_implicit_this_capture);
2058-
}
2059-
SyclKernelFieldChecker checker(*this);
2060-
SyclKernelDeclCreator kernel_decl(
2061-
*this, checker, KernelName, KernelObj->getLocation(),
2062-
KernelCallerFunc->isInlined(), KernelCallerFunc->hasAttr<SYCLSimdAttr>());
2082+
SyclKernelDeclCreator kernel_decl(*this, KernelName, KernelObj->getLocation(),
2083+
KernelCallerFunc->isInlined(),
2084+
KernelCallerFunc->hasAttr<SYCLSimdAttr>());
20632085
SyclKernelBodyCreator kernel_body(*this, kernel_decl, KernelObj,
20642086
KernelCallerFunc);
20652087
SyclKernelIntHeaderCreator int_header(
20662088
*this, getSyclIntegrationHeader(), KernelObj,
20672089
calculateKernelNameType(Context, KernelCallerFunc), KernelName,
20682090
StableName);
20692091

2070-
ConstructingOpenCLKernel = true;
20712092
KernelObjVisitor Visitor{*this};
2072-
Visitor.VisitRecordBases(KernelObj, checker, kernel_decl, kernel_body,
2073-
int_header);
2074-
Visitor.VisitRecordFields(KernelObj, checker, kernel_decl, kernel_body,
2075-
int_header);
2076-
ConstructingOpenCLKernel = false;
2093+
Visitor.VisitRecordBases(KernelObj, kernel_decl, kernel_body, int_header);
2094+
Visitor.VisitRecordFields(KernelObj, kernel_decl, kernel_body, int_header);
20772095
}
20782096

20792097
// This function marks all the callees of explicit SIMD kernel
@@ -2242,7 +2260,7 @@ Sema::DeviceDiagBuilder Sema::SYCLDiagIfDeviceCode(SourceLocation Loc,
22422260
"Should only be called during SYCL compilation");
22432261
FunctionDecl *FD = dyn_cast<FunctionDecl>(getCurLexicalContext());
22442262
DeviceDiagBuilder::Kind DiagKind = [this, FD] {
2245-
if (ConstructingOpenCLKernel)
2263+
if (DiagnosingSYCLKernel)
22462264
return DeviceDiagBuilder::K_ImmediateWithCallStack;
22472265
if (!FD)
22482266
return DeviceDiagBuilder::K_Nop;
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// RUN: %clang_cc1 -fsycl -fsycl-is-device -fsyntax-only -verify %s
2+
3+
template <typename Name, typename F>
4+
__attribute__((sycl_kernel)) void kernel(F kernelFunc) {
5+
kernelFunc();
6+
}
7+
8+
template <typename Name, typename F>
9+
void uses_kernel(F kernelFunc) {
10+
// expected-error@+1{{kernel parameter must be a lambda or function object}}
11+
kernel<Name>(kernelFunc);
12+
}
13+
14+
void func() {}
15+
16+
template <typename Name>
17+
void kernel_wrapper() {
18+
// expected-note@+1{{in instantiation of function template specialization}}
19+
uses_kernel<Name>(func);
20+
}
21+
22+
void use() {
23+
// expected-note@+1{{in instantiation of function template specialization}}
24+
kernel_wrapper<class Foo>();
25+
}

clang/test/SemaSYCL/lambda_implicit_capture_this.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ class Class {
1313
};
1414

1515
void Class::function() {
16+
// expected-note@+1{{used here}}
1617
kernel<class kernel_wrapper>(
1718
[=]() {
1819
int acc[1] = {5};

0 commit comments

Comments
 (0)