Skip to content

Commit 8ea8e7f

Browse files
authored
[SYCL] Basic diagnostics for the sycl_kernel_entry_point attribute. (#120327)
The `sycl_kernel_entry_point` attribute is used to declare a function that defines a pattern for an offload kernel entry point. The attribute requires a single type argument that specifies a class type that meets the requirements for a SYCL kernel name as described in section 5.2, "Naming of kernels", of the SYCL 2020 specification. A unique kernel name type is required for each function declared with the attribute. The attribute may not first appear on a declaration that follows a definition of the function. The function is required to have a non-deduced `void` return type. The function must not be a non-static member function, be deleted or defaulted, be declared with the `constexpr` or `consteval` specifiers, be declared with the `[[noreturn]]` attribute, be a coroutine, or accept variadic arguments. Diagnostics are not yet provided for the following: - Use of a type as a kernel name that does not satisfy the forward declarability requirements specified in section 5.2, "Naming of kernels", of the SYCL 2020 specification. - Use of a type as a parameter of the attributed function that does not satisfy the kernel parameter requirements specified in section 4.12.4, "Rules for parameter passing to kernels", of the SYCL 2020 specification (each such function parameter constitutes a kernel parameter). - Use of language features that are not permitted in device functions as specified in section 5.4, "Language restrictions for device functions", of the SYCL 2020 specification. There are several issues noted by various FIXME comments. - The diagnostic generated for kernel name conflicts needs additional work to better detail the relevant source locations; such as the location of each declaration as well as the original source of each kernel name. - A number of the tests illustrate spurious errors being produced due to attributes that appertain to function templates being instantiated too early (during overload resolution as opposed to after an overload is selected). Included changes allow the `SYCLKernelEntryPointAttr` attribute to be marked as invalid if a `sycl_kernel_entry_point` attribute is used incorrectly. This is intended to prevent trying to emit an offload kernel entry point without having to mark the associated function as invalid since doing so would affect overload resolution; which this attribute should not do. Unfortunately, Clang eagerly instantiates attributes that appertain to functions with the result that errors might be issued for function declarations that are never selected by overload resolution. Tests have been added to demonstrate this. Further work will be needed to address these issues (for this and other attributes).
1 parent d797d94 commit 8ea8e7f

18 files changed

+966
-25
lines changed

clang/include/clang/AST/ASTContext.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3360,6 +3360,16 @@ class ASTContext : public RefCountedBase<ASTContext> {
33603360
/// this function.
33613361
void registerSYCLEntryPointFunction(FunctionDecl *FD);
33623362

3363+
/// Given a type used as a SYCL kernel name, returns a reference to the
3364+
/// metadata generated from the corresponding SYCL kernel entry point.
3365+
/// Aborts if the provided type is not a registered SYCL kernel name.
3366+
const SYCLKernelInfo &getSYCLKernelInfo(QualType T) const;
3367+
3368+
/// Returns a pointer to the metadata generated from the corresponding
3369+
/// SYCLkernel entry point if the provided type corresponds to a registered
3370+
/// SYCL kernel name. Returns a null pointer otherwise.
3371+
const SYCLKernelInfo *findSYCLKernelInfo(QualType T) const;
3372+
33633373
//===--------------------------------------------------------------------===//
33643374
// Statistics
33653375
//===--------------------------------------------------------------------===//

clang/include/clang/Basic/Attr.td

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1516,11 +1516,22 @@ def SYCLKernel : InheritableAttr {
15161516

15171517
def SYCLKernelEntryPoint : InheritableAttr {
15181518
let Spellings = [Clang<"sycl_kernel_entry_point">];
1519-
let Args = [TypeArgument<"KernelName">];
1519+
let Args = [
1520+
// KernelName is required and specifies the kernel name type.
1521+
TypeArgument<"KernelName">,
1522+
// InvalidAttr is a fake argument used to track whether the
1523+
// semantic requirements of the attribute have been satisified.
1524+
// A fake argument is used to enable serialization support.
1525+
DefaultBoolArgument<"Invalid", /*default=*/0, /*fake=*/1>
1526+
];
15201527
let Subjects = SubjectList<[Function], ErrorDiag>;
15211528
let TemplateDependent = 1;
15221529
let LangOpts = [SYCLHost, SYCLDevice];
15231530
let Documentation = [SYCLKernelEntryPointDocs];
1531+
let AdditionalMembers = [{
1532+
void setInvalidAttr() { invalid = true; }
1533+
bool isInvalidAttr() const { return invalid; }
1534+
}];
15241535
}
15251536

15261537
def SYCLSpecialClass: InheritableAttr {

clang/include/clang/Basic/AttrDocs.td

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -475,7 +475,7 @@ not first appear on a declaration that follows a definition of the function.
475475
The attribute only appertains to functions and only those that meet the
476476
following requirements.
477477

478-
* Has a ``void`` return type.
478+
* Has a non-deduced ``void`` return type.
479479
* Is not a non-static member function, constructor, or destructor.
480480
* Is not a C variadic function.
481481
* Is not a coroutine.

clang/include/clang/Basic/DiagnosticGroups.td

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -648,6 +648,7 @@ def PoundPragmaMessage : DiagGroup<"#pragma-messages">,
648648
def : DiagGroup<"redundant-decls">;
649649
def RedeclaredClassMember : DiagGroup<"redeclared-class-member">;
650650
def GNURedeclaredEnum : DiagGroup<"gnu-redeclared-enum">;
651+
def RedundantAttribute : DiagGroup<"redundant-attribute">;
651652
def RedundantMove : DiagGroup<"redundant-move">;
652653
def Register : DiagGroup<"register", [DeprecatedRegister]>;
653654
def ReturnTypeCLinkage : DiagGroup<"return-type-c-linkage">;

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12429,6 +12429,33 @@ def err_sycl_special_type_num_init_method : Error<
1242912429
"types with 'sycl_special_class' attribute must have one and only one '__init' "
1243012430
"method defined">;
1243112431

12432+
// SYCL kernel entry point diagnostics
12433+
def err_sycl_entry_point_invalid : Error<
12434+
"'sycl_kernel_entry_point' attribute cannot be applied to a"
12435+
" %select{non-static member function|variadic function|deleted function|"
12436+
"defaulted function|constexpr function|consteval function|"
12437+
"function declared with the 'noreturn' attribute|coroutine}0">;
12438+
def err_sycl_entry_point_invalid_redeclaration : Error<
12439+
"'sycl_kernel_entry_point' kernel name argument does not match prior"
12440+
" declaration%diff{: $ vs $|}0,1">;
12441+
def err_sycl_kernel_name_conflict : Error<
12442+
"'sycl_kernel_entry_point' kernel name argument conflicts with a previous"
12443+
" declaration">;
12444+
def warn_sycl_kernel_name_not_a_class_type : Warning<
12445+
"%0 is not a valid SYCL kernel name type; a non-union class type is required">,
12446+
InGroup<DiagGroup<"nonportable-sycl">>, DefaultError;
12447+
def warn_sycl_entry_point_redundant_declaration : Warning<
12448+
"redundant 'sycl_kernel_entry_point' attribute">, InGroup<RedundantAttribute>;
12449+
def err_sycl_entry_point_after_definition : Error<
12450+
"'sycl_kernel_entry_point' attribute cannot be added to a function after the"
12451+
" function is defined">;
12452+
def err_sycl_entry_point_return_type : Error<
12453+
"'sycl_kernel_entry_point' attribute only applies to functions with a"
12454+
" 'void' return type">;
12455+
def err_sycl_entry_point_deduced_return_type : Error<
12456+
"'sycl_kernel_entry_point' attribute only applies to functions with a"
12457+
" non-deduced 'void' return type">;
12458+
1243212459
def warn_cuda_maxclusterrank_sm_90 : Warning<
1243312460
"maxclusterrank requires sm_90 or higher, CUDA arch provided: %0, ignoring "
1243412461
"%1 attribute">, InGroup<IgnoredAttributes>;

clang/include/clang/Sema/SemaSYCL.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,8 @@ class SemaSYCL : public SemaBase {
6363

6464
void handleKernelAttr(Decl *D, const ParsedAttr &AL);
6565
void handleKernelEntryPointAttr(Decl *D, const ParsedAttr &AL);
66+
67+
void CheckSYCLEntryPointFunctionDecl(FunctionDecl *FD);
6668
};
6769

6870
} // namespace clang

clang/lib/AST/ASTContext.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14502,6 +14502,19 @@ void ASTContext::registerSYCLEntryPointFunction(FunctionDecl *FD) {
1450214502
std::make_pair(KernelNameType, BuildSYCLKernelInfo(KernelNameType, FD)));
1450314503
}
1450414504

14505+
const SYCLKernelInfo &ASTContext::getSYCLKernelInfo(QualType T) const {
14506+
CanQualType KernelNameType = getCanonicalType(T);
14507+
return SYCLKernels.at(KernelNameType);
14508+
}
14509+
14510+
const SYCLKernelInfo *ASTContext::findSYCLKernelInfo(QualType T) const {
14511+
CanQualType KernelNameType = getCanonicalType(T);
14512+
auto IT = SYCLKernels.find(KernelNameType);
14513+
if (IT != SYCLKernels.end())
14514+
return &IT->second;
14515+
return nullptr;
14516+
}
14517+
1450514518
OMPTraitInfo &ASTContext::getNewOMPTraitInfo() {
1450614519
OMPTraitInfoVector.emplace_back(new OMPTraitInfo());
1450714520
return *OMPTraitInfoVector.back();

clang/lib/Sema/SemaDecl.cpp

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
#include "clang/Sema/SemaOpenMP.h"
5353
#include "clang/Sema/SemaPPC.h"
5454
#include "clang/Sema/SemaRISCV.h"
55+
#include "clang/Sema/SemaSYCL.h"
5556
#include "clang/Sema/SemaSwift.h"
5657
#include "clang/Sema/SemaWasm.h"
5758
#include "clang/Sema/Template.h"
@@ -2923,7 +2924,7 @@ static void checkNewAttributesAfterDef(Sema &S, Decl *New, const Decl *Old) {
29232924

29242925
AttrVec &NewAttributes = New->getAttrs();
29252926
for (unsigned I = 0, E = NewAttributes.size(); I != E;) {
2926-
const Attr *NewAttribute = NewAttributes[I];
2927+
Attr *NewAttribute = NewAttributes[I];
29272928

29282929
if (isa<AliasAttr>(NewAttribute) || isa<IFuncAttr>(NewAttribute)) {
29292930
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(New)) {
@@ -3018,6 +3019,16 @@ static void checkNewAttributesAfterDef(Sema &S, Decl *New, const Decl *Old) {
30183019
// declarations after definitions.
30193020
++I;
30203021
continue;
3022+
} else if (isa<SYCLKernelEntryPointAttr>(NewAttribute)) {
3023+
// Elevate latent uses of the sycl_kernel_entry_point attribute to an
3024+
// error since the definition will have already been created without
3025+
// the semantic effects of the attribute having been applied.
3026+
S.Diag(NewAttribute->getLocation(),
3027+
diag::err_sycl_entry_point_after_definition);
3028+
S.Diag(Def->getLocation(), diag::note_previous_definition);
3029+
cast<SYCLKernelEntryPointAttr>(NewAttribute)->setInvalidAttr();
3030+
++I;
3031+
continue;
30213032
}
30223033

30233034
S.Diag(NewAttribute->getLocation(),
@@ -12142,8 +12153,8 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
1214212153
if (LangOpts.OpenMP)
1214312154
OpenMP().ActOnFinishedFunctionDefinitionInOpenMPAssumeScope(NewFD);
1214412155

12145-
if (LangOpts.isSYCL() && NewFD->hasAttr<SYCLKernelEntryPointAttr>())
12146-
getASTContext().registerSYCLEntryPointFunction(NewFD);
12156+
if (NewFD->hasAttr<SYCLKernelEntryPointAttr>())
12157+
SYCL().CheckSYCLEntryPointFunctionDecl(NewFD);
1214712158

1214812159
// Semantic checking for this function declaration (in isolation).
1214912160

@@ -15975,6 +15986,25 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
1597515986
CheckCoroutineWrapper(FD);
1597615987
}
1597715988

15989+
// Diagnose invalid SYCL kernel entry point function declarations.
15990+
if (FD && !FD->isInvalidDecl() && FD->hasAttr<SYCLKernelEntryPointAttr>()) {
15991+
SYCLKernelEntryPointAttr *SKEPAttr =
15992+
FD->getAttr<SYCLKernelEntryPointAttr>();
15993+
if (FD->isDefaulted()) {
15994+
Diag(SKEPAttr->getLocation(), diag::err_sycl_entry_point_invalid)
15995+
<< /*defaulted function*/ 3;
15996+
SKEPAttr->setInvalidAttr();
15997+
} else if (FD->isDeleted()) {
15998+
Diag(SKEPAttr->getLocation(), diag::err_sycl_entry_point_invalid)
15999+
<< /*deleted function*/ 2;
16000+
SKEPAttr->setInvalidAttr();
16001+
} else if (FSI->isCoroutine()) {
16002+
Diag(SKEPAttr->getLocation(), diag::err_sycl_entry_point_invalid)
16003+
<< /*coroutine*/ 7;
16004+
SKEPAttr->setInvalidAttr();
16005+
}
16006+
}
16007+
1597816008
{
1597916009
// Do not call PopExpressionEvaluationContext() if it is a lambda because
1598016010
// one is already popped when finishing the lambda in BuildLambdaExpr().

clang/lib/Sema/SemaLambda.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include "clang/Sema/SemaCUDA.h"
2525
#include "clang/Sema/SemaInternal.h"
2626
#include "clang/Sema/SemaOpenMP.h"
27+
#include "clang/Sema/SemaSYCL.h"
2728
#include "clang/Sema/Template.h"
2829
#include "llvm/ADT/STLExtras.h"
2930
#include <optional>
@@ -1948,6 +1949,10 @@ ExprResult Sema::BuildCaptureInit(const Capture &Cap,
19481949

19491950
ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body) {
19501951
LambdaScopeInfo LSI = *cast<LambdaScopeInfo>(FunctionScopes.back());
1952+
1953+
if (LSI.CallOperator->hasAttr<SYCLKernelEntryPointAttr>())
1954+
SYCL().CheckSYCLEntryPointFunctionDecl(LSI.CallOperator);
1955+
19511956
ActOnFinishFunctionBody(LSI.CallOperator, Body);
19521957

19531958
return BuildLambdaExpr(StartLoc, Body->getEndLoc(), &LSI);

clang/lib/Sema/SemaSYCL.cpp

Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@
1010

1111
#include "clang/Sema/SemaSYCL.h"
1212
#include "clang/AST/Mangle.h"
13+
#include "clang/AST/SYCLKernelInfo.h"
1314
#include "clang/AST/TypeOrdering.h"
15+
#include "clang/Basic/Diagnostic.h"
1416
#include "clang/Sema/Attr.h"
1517
#include "clang/Sema/ParsedAttr.h"
1618
#include "clang/Sema/Sema.h"
@@ -206,3 +208,157 @@ void SemaSYCL::handleKernelEntryPointAttr(Decl *D, const ParsedAttr &AL) {
206208
D->addAttr(::new (SemaRef.Context)
207209
SYCLKernelEntryPointAttr(SemaRef.Context, AL, TSI));
208210
}
211+
212+
// Given a potentially qualified type, SourceLocationForUserDeclaredType()
213+
// returns the source location of the canonical declaration of the unqualified
214+
// desugared user declared type, if any. For non-user declared types, an
215+
// invalid source location is returned. The intended usage of this function
216+
// is to identify an appropriate source location, if any, for a
217+
// "entity declared here" diagnostic note.
218+
static SourceLocation SourceLocationForUserDeclaredType(QualType QT) {
219+
SourceLocation Loc;
220+
const Type *T = QT->getUnqualifiedDesugaredType();
221+
if (const TagType *TT = dyn_cast<TagType>(T))
222+
Loc = TT->getDecl()->getLocation();
223+
else if (const ObjCInterfaceType *ObjCIT = dyn_cast<ObjCInterfaceType>(T))
224+
Loc = ObjCIT->getDecl()->getLocation();
225+
return Loc;
226+
}
227+
228+
static bool CheckSYCLKernelName(Sema &S, SourceLocation Loc,
229+
QualType KernelName) {
230+
assert(!KernelName->isDependentType());
231+
232+
if (!KernelName->isStructureOrClassType()) {
233+
// SYCL 2020 section 5.2, "Naming of kernels", only requires that the
234+
// kernel name be a C++ typename. However, the definition of "kernel name"
235+
// in the glossary states that a kernel name is a class type. Neither
236+
// section explicitly states whether the kernel name type can be
237+
// cv-qualified. For now, kernel name types are required to be class types
238+
// and that they may be cv-qualified. The following issue requests
239+
// clarification from the SYCL WG.
240+
// https://github.com/KhronosGroup/SYCL-Docs/issues/568
241+
S.Diag(Loc, diag::warn_sycl_kernel_name_not_a_class_type) << KernelName;
242+
SourceLocation DeclTypeLoc = SourceLocationForUserDeclaredType(KernelName);
243+
if (DeclTypeLoc.isValid())
244+
S.Diag(DeclTypeLoc, diag::note_entity_declared_at) << KernelName;
245+
return true;
246+
}
247+
248+
return false;
249+
}
250+
251+
void SemaSYCL::CheckSYCLEntryPointFunctionDecl(FunctionDecl *FD) {
252+
// Ensure that all attributes present on the declaration are consistent
253+
// and warn about any redundant ones.
254+
SYCLKernelEntryPointAttr *SKEPAttr = nullptr;
255+
for (auto *SAI : FD->specific_attrs<SYCLKernelEntryPointAttr>()) {
256+
if (!SKEPAttr) {
257+
SKEPAttr = SAI;
258+
continue;
259+
}
260+
if (!getASTContext().hasSameType(SAI->getKernelName(),
261+
SKEPAttr->getKernelName())) {
262+
Diag(SAI->getLocation(), diag::err_sycl_entry_point_invalid_redeclaration)
263+
<< SAI->getKernelName() << SKEPAttr->getKernelName();
264+
Diag(SKEPAttr->getLocation(), diag::note_previous_attribute);
265+
SAI->setInvalidAttr();
266+
} else {
267+
Diag(SAI->getLocation(),
268+
diag::warn_sycl_entry_point_redundant_declaration);
269+
Diag(SKEPAttr->getLocation(), diag::note_previous_attribute);
270+
}
271+
}
272+
assert(SKEPAttr && "Missing sycl_kernel_entry_point attribute");
273+
274+
// Ensure the kernel name type is valid.
275+
if (!SKEPAttr->getKernelName()->isDependentType() &&
276+
CheckSYCLKernelName(SemaRef, SKEPAttr->getLocation(),
277+
SKEPAttr->getKernelName()))
278+
SKEPAttr->setInvalidAttr();
279+
280+
// Ensure that an attribute present on the previous declaration
281+
// matches the one on this declaration.
282+
FunctionDecl *PrevFD = FD->getPreviousDecl();
283+
if (PrevFD && !PrevFD->isInvalidDecl()) {
284+
const auto *PrevSKEPAttr = PrevFD->getAttr<SYCLKernelEntryPointAttr>();
285+
if (PrevSKEPAttr && !PrevSKEPAttr->isInvalidAttr()) {
286+
if (!getASTContext().hasSameType(SKEPAttr->getKernelName(),
287+
PrevSKEPAttr->getKernelName())) {
288+
Diag(SKEPAttr->getLocation(),
289+
diag::err_sycl_entry_point_invalid_redeclaration)
290+
<< SKEPAttr->getKernelName() << PrevSKEPAttr->getKernelName();
291+
Diag(PrevSKEPAttr->getLocation(), diag::note_previous_decl) << PrevFD;
292+
SKEPAttr->setInvalidAttr();
293+
}
294+
}
295+
}
296+
297+
if (const auto *MD = dyn_cast<CXXMethodDecl>(FD)) {
298+
if (!MD->isStatic()) {
299+
Diag(SKEPAttr->getLocation(), diag::err_sycl_entry_point_invalid)
300+
<< /*non-static member function*/ 0;
301+
SKEPAttr->setInvalidAttr();
302+
}
303+
}
304+
305+
if (FD->isVariadic()) {
306+
Diag(SKEPAttr->getLocation(), diag::err_sycl_entry_point_invalid)
307+
<< /*variadic function*/ 1;
308+
SKEPAttr->setInvalidAttr();
309+
}
310+
311+
if (FD->isDefaulted()) {
312+
Diag(SKEPAttr->getLocation(), diag::err_sycl_entry_point_invalid)
313+
<< /*defaulted function*/ 3;
314+
SKEPAttr->setInvalidAttr();
315+
} else if (FD->isDeleted()) {
316+
Diag(SKEPAttr->getLocation(), diag::err_sycl_entry_point_invalid)
317+
<< /*deleted function*/ 2;
318+
SKEPAttr->setInvalidAttr();
319+
}
320+
321+
if (FD->isConsteval()) {
322+
Diag(SKEPAttr->getLocation(), diag::err_sycl_entry_point_invalid)
323+
<< /*consteval function*/ 5;
324+
SKEPAttr->setInvalidAttr();
325+
} else if (FD->isConstexpr()) {
326+
Diag(SKEPAttr->getLocation(), diag::err_sycl_entry_point_invalid)
327+
<< /*constexpr function*/ 4;
328+
SKEPAttr->setInvalidAttr();
329+
}
330+
331+
if (FD->isNoReturn()) {
332+
Diag(SKEPAttr->getLocation(), diag::err_sycl_entry_point_invalid)
333+
<< /*function declared with the 'noreturn' attribute*/ 6;
334+
SKEPAttr->setInvalidAttr();
335+
}
336+
337+
if (FD->getReturnType()->isUndeducedType()) {
338+
Diag(SKEPAttr->getLocation(),
339+
diag::err_sycl_entry_point_deduced_return_type);
340+
SKEPAttr->setInvalidAttr();
341+
} else if (!FD->getReturnType()->isDependentType() &&
342+
!FD->getReturnType()->isVoidType()) {
343+
Diag(SKEPAttr->getLocation(), diag::err_sycl_entry_point_return_type);
344+
SKEPAttr->setInvalidAttr();
345+
}
346+
347+
if (!FD->isInvalidDecl() && !FD->isTemplated() &&
348+
!SKEPAttr->isInvalidAttr()) {
349+
const SYCLKernelInfo *SKI =
350+
getASTContext().findSYCLKernelInfo(SKEPAttr->getKernelName());
351+
if (SKI) {
352+
if (!declaresSameEntity(FD, SKI->getKernelEntryPointDecl())) {
353+
// FIXME: This diagnostic should include the origin of the kernel
354+
// FIXME: names; not just the locations of the conflicting declarations.
355+
Diag(FD->getLocation(), diag::err_sycl_kernel_name_conflict);
356+
Diag(SKI->getKernelEntryPointDecl()->getLocation(),
357+
diag::note_previous_declaration);
358+
SKEPAttr->setInvalidAttr();
359+
}
360+
} else {
361+
getASTContext().registerSYCLEntryPointFunction(FD);
362+
}
363+
}
364+
}

clang/lib/Serialization/ASTReaderDecl.cpp

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1134,8 +1134,19 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) {
11341134
// the presence of a sycl_kernel_entry_point attribute, register it so that
11351135
// associated metadata is recreated.
11361136
if (FD->hasAttr<SYCLKernelEntryPointAttr>()) {
1137+
auto *SKEPAttr = FD->getAttr<SYCLKernelEntryPointAttr>();
11371138
ASTContext &C = Reader.getContext();
1138-
C.registerSYCLEntryPointFunction(FD);
1139+
const SYCLKernelInfo *SKI = C.findSYCLKernelInfo(SKEPAttr->getKernelName());
1140+
if (SKI) {
1141+
if (!declaresSameEntity(FD, SKI->getKernelEntryPointDecl())) {
1142+
Reader.Diag(FD->getLocation(), diag::err_sycl_kernel_name_conflict);
1143+
Reader.Diag(SKI->getKernelEntryPointDecl()->getLocation(),
1144+
diag::note_previous_declaration);
1145+
SKEPAttr->setInvalidAttr();
1146+
}
1147+
} else {
1148+
C.registerSYCLEntryPointFunction(FD);
1149+
}
11391150
}
11401151
}
11411152

0 commit comments

Comments
 (0)