https://github.com/tahonermann updated https://github.com/llvm/llvm-project/pull/120327
>From 6ed96d3bf22c5da5af995ea5ffe083baf91594bb Mon Sep 17 00:00:00 2001 From: Tom Honermann <tom.honerm...@intel.com> Date: Fri, 1 Nov 2024 16:03:24 -0700 Subject: [PATCH 1/8] [SYCL] Basic diagnostics for the sycl_kernel_entry_point attribute. 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 `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). --- clang/include/clang/AST/ASTContext.h | 10 + clang/include/clang/Basic/DiagnosticGroups.td | 1 + .../clang/Basic/DiagnosticSemaKinds.td | 23 ++ clang/include/clang/Sema/SemaSYCL.h | 2 + clang/lib/AST/ASTContext.cpp | 13 + clang/lib/Sema/SemaDecl.cpp | 30 ++- clang/lib/Sema/SemaSYCL.cpp | 126 +++++++++ clang/lib/Sema/SemaTemplate.cpp | 2 + clang/lib/Serialization/ASTReaderDecl.cpp | 13 +- .../ast-dump-sycl-kernel-entry-point.cpp | 23 +- ...-kernel-entry-point-attr-appertainment.cpp | 255 ++++++++++++++++++ .../sycl-kernel-entry-point-attr-grammar.cpp | 15 -- ...el-entry-point-attr-kernel-name-module.cpp | 104 +++++++ ...ernel-entry-point-attr-kernel-name-pch.cpp | 36 +++ ...cl-kernel-entry-point-attr-kernel-name.cpp | 87 ++++++ .../sycl-kernel-entry-point-attr-sfinae.cpp | 65 +++++ 16 files changed, 784 insertions(+), 21 deletions(-) create mode 100644 clang/test/SemaSYCL/sycl-kernel-entry-point-attr-appertainment.cpp create mode 100644 clang/test/SemaSYCL/sycl-kernel-entry-point-attr-kernel-name-module.cpp create mode 100644 clang/test/SemaSYCL/sycl-kernel-entry-point-attr-kernel-name-pch.cpp create mode 100644 clang/test/SemaSYCL/sycl-kernel-entry-point-attr-kernel-name.cpp create mode 100644 clang/test/SemaSYCL/sycl-kernel-entry-point-attr-sfinae.cpp diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h index 1e89a6805ce9c6..0e07c5d6ce8fba 100644 --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -3360,6 +3360,16 @@ class ASTContext : public RefCountedBase<ASTContext> { /// this function. void registerSYCLEntryPointFunction(FunctionDecl *FD); + /// Given a type used as a SYCL kernel name, returns a reference to the + /// metadata generated from the corresponding SYCL kernel entry point. + /// Aborts if the provided type is not a registered SYCL kernel name. + const SYCLKernelInfo &getSYCLKernelInfo(QualType T) const; + + /// Returns a pointer to the metadata generated from the corresponding + /// SYCLkernel entry point if the provided type corresponds to a registered + /// SYCL kernel name. Returns a null pointer otherwise. + const SYCLKernelInfo *findSYCLKernelInfo(QualType T) const; + //===--------------------------------------------------------------------===// // Statistics //===--------------------------------------------------------------------===// diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td index 3ac490d30371b1..594e99a19b64d6 100644 --- a/clang/include/clang/Basic/DiagnosticGroups.td +++ b/clang/include/clang/Basic/DiagnosticGroups.td @@ -648,6 +648,7 @@ def PoundPragmaMessage : DiagGroup<"#pragma-messages">, def : DiagGroup<"redundant-decls">; def RedeclaredClassMember : DiagGroup<"redeclared-class-member">; def GNURedeclaredEnum : DiagGroup<"gnu-redeclared-enum">; +def RedundantAttribute : DiagGroup<"redundant-attribute">; def RedundantMove : DiagGroup<"redundant-move">; def Register : DiagGroup<"register", [DeprecatedRegister]>; def ReturnTypeCLinkage : DiagGroup<"return-type-c-linkage">; diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 9344b620779b84..2495fbc4ce0765 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -12408,6 +12408,29 @@ def err_sycl_special_type_num_init_method : Error< "types with 'sycl_special_class' attribute must have one and only one '__init' " "method defined">; +// SYCL kernel entry point diagnostics +def err_sycl_entry_point_invalid : Error< + "'sycl_kernel_entry_point' attribute cannot be applied to a" + " %select{non-static member|variadic|deleted|defaulted|constexpr|consteval|" + "noreturn|coroutine}0 function">; +def err_sycl_entry_point_invalid_redeclaration : Error< + "'sycl_kernel_entry_point' kernel name argument does not match prior" + " declaration%diff{: $ vs $|}0,1">; +def err_sycl_kernel_name_conflict : Error< + "'sycl_kernel_entry_point' kernel name argument conflicts with a previous" + " declaration">; +def warn_sycl_kernel_name_not_a_class_type : Warning< + "%0 is not a valid SYCL kernel name type; a class type is required">, + InGroup<DiagGroup<"nonportable-sycl">>, DefaultError; +def warn_sycl_entry_point_redundant_declaration : Warning< + "redundant 'sycl_kernel_entry_point' attribute">, InGroup<RedundantAttribute>; +def err_sycl_entry_point_after_definition : Error< + "'sycl_kernel_entry_point' attribute cannot be added to a function after the" + " function is defined">; +def err_sycl_entry_point_return_type : Error< + "'sycl_kernel_entry_point' attribute only applies to functions with a" + " 'void' return type">; + def warn_cuda_maxclusterrank_sm_90 : Warning< "maxclusterrank requires sm_90 or higher, CUDA arch provided: %0, ignoring " "%1 attribute">, InGroup<IgnoredAttributes>; diff --git a/clang/include/clang/Sema/SemaSYCL.h b/clang/include/clang/Sema/SemaSYCL.h index c9f3358124eda7..5bb0de40c886c7 100644 --- a/clang/include/clang/Sema/SemaSYCL.h +++ b/clang/include/clang/Sema/SemaSYCL.h @@ -63,6 +63,8 @@ class SemaSYCL : public SemaBase { void handleKernelAttr(Decl *D, const ParsedAttr &AL); void handleKernelEntryPointAttr(Decl *D, const ParsedAttr &AL); + + void CheckSYCLEntryPointFunctionDecl(FunctionDecl *FD); }; } // namespace clang diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 6ec927e13a7552..3c9614c6cee2bb 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -14463,6 +14463,19 @@ void ASTContext::registerSYCLEntryPointFunction(FunctionDecl *FD) { std::make_pair(KernelNameType, BuildSYCLKernelInfo(KernelNameType, FD))); } +const SYCLKernelInfo &ASTContext::getSYCLKernelInfo(QualType T) const { + CanQualType KernelNameType = getCanonicalType(T); + return SYCLKernels.at(KernelNameType); +} + +const SYCLKernelInfo *ASTContext::findSYCLKernelInfo(QualType T) const { + CanQualType KernelNameType = getCanonicalType(T); + auto IT = SYCLKernels.find(KernelNameType); + if (IT != SYCLKernels.end()) + return &IT->second; + return nullptr; +} + OMPTraitInfo &ASTContext::getNewOMPTraitInfo() { OMPTraitInfoVector.emplace_back(new OMPTraitInfo()); return *OMPTraitInfoVector.back(); diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 55e891e3acf20d..aea8bb112c0271 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -53,6 +53,7 @@ #include "clang/Sema/SemaPPC.h" #include "clang/Sema/SemaRISCV.h" #include "clang/Sema/SemaSwift.h" +#include "clang/Sema/SemaSYCL.h" #include "clang/Sema/SemaWasm.h" #include "clang/Sema/Template.h" #include "llvm/ADT/STLForwardCompat.h" @@ -3018,6 +3019,15 @@ static void checkNewAttributesAfterDef(Sema &S, Decl *New, const Decl *Old) { // declarations after definitions. ++I; continue; + } else if (isa<SYCLKernelEntryPointAttr>(NewAttribute)) { + // Elevate latent uses of the sycl_kernel_entry_point attribute to an + // error since the definition will have already been created without + // the semantic effects of the attribute having been applied. + S.Diag(NewAttribute->getLocation(), + diag::err_sycl_entry_point_after_definition); + S.Diag(Def->getLocation(), diag::note_previous_definition); + ++I; + continue; } S.Diag(NewAttribute->getLocation(), @@ -12146,7 +12156,7 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, OpenMP().ActOnFinishedFunctionDefinitionInOpenMPAssumeScope(NewFD); if (LangOpts.isSYCL() && NewFD->hasAttr<SYCLKernelEntryPointAttr>()) - getASTContext().registerSYCLEntryPointFunction(NewFD); + SYCL().CheckSYCLEntryPointFunctionDecl(NewFD); // Semantic checking for this function declaration (in isolation). @@ -15978,6 +15988,24 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, CheckCoroutineWrapper(FD); } + // Diagnose invalid SYCL kernel entry point function declarations. + if (FD && !FD->isInvalidDecl() && !FD->isTemplated() && + FD->hasAttr<SYCLKernelEntryPointAttr>()) { + if (FD->isDeleted()) { + Diag(FD->getAttr<SYCLKernelEntryPointAttr>()->getLocation(), + diag::err_sycl_entry_point_invalid) + << /*deleted function*/2; + } else if (FD->isDefaulted()) { + Diag(FD->getAttr<SYCLKernelEntryPointAttr>()->getLocation(), + diag::err_sycl_entry_point_invalid) + << /*defaulted function*/3; + } else if (FSI->isCoroutine()) { + Diag(FD->getAttr<SYCLKernelEntryPointAttr>()->getLocation(), + diag::err_sycl_entry_point_invalid) + << /*coroutine*/7; + } + } + { // Do not call PopExpressionEvaluationContext() if it is a lambda because // one is already popped when finishing the lambda in BuildLambdaExpr(). diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp index d4fddeb01d0fc8..04ab8c28e14108 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -10,7 +10,9 @@ #include "clang/Sema/SemaSYCL.h" #include "clang/AST/Mangle.h" +#include "clang/AST/SYCLKernelInfo.h" #include "clang/AST/TypeOrdering.h" +#include "clang/Basic/Diagnostic.h" #include "clang/Sema/Attr.h" #include "clang/Sema/ParsedAttr.h" #include "clang/Sema/Sema.h" @@ -206,3 +208,127 @@ void SemaSYCL::handleKernelEntryPointAttr(Decl *D, const ParsedAttr &AL) { D->addAttr(::new (SemaRef.Context) SYCLKernelEntryPointAttr(SemaRef.Context, AL, TSI)); } + +static SourceLocation SourceLocationForType(QualType QT) { + SourceLocation Loc; + const Type *T = QT->getUnqualifiedDesugaredType(); + if (const TagType *TT = dyn_cast<TagType>(T)) + Loc = TT->getDecl()->getLocation(); + else if (const ObjCInterfaceType *ObjCIT = dyn_cast<ObjCInterfaceType>(T)) + Loc = ObjCIT->getDecl()->getLocation(); + return Loc; +} + +static bool CheckSYCLKernelName(Sema &S, SourceLocation Loc, + QualType KernelName) { + assert(!KernelName->isDependentType()); + + if (!KernelName->isStructureOrClassType()) { + // SYCL 2020 section 5.2, "Naming of kernels", only requires that the + // kernel name be a C++ typename. However, the definition of "kernel name" + // in the glossary states that a kernel name is a class type. Neither + // section explicitly states whether the kernel name type can be + // cv-qualified. For now, kernel name types are required to be class types + // and that they may be cv-qualified. The following issue requests + // clarification from the SYCL WG. + // https://github.com/KhronosGroup/SYCL-Docs/issues/568 + S.Diag(Loc, diag::warn_sycl_kernel_name_not_a_class_type) << KernelName; + SourceLocation DeclTypeLoc = SourceLocationForType(KernelName); + if (DeclTypeLoc.isValid()) + S.Diag(DeclTypeLoc, diag::note_entity_declared_at) + << KernelName; + return true; + } + + return false; +} + +void SemaSYCL::CheckSYCLEntryPointFunctionDecl(FunctionDecl *FD) { + // Ensure that all attributes present on the declaration are consistent + // and warn about any redundant ones. + const SYCLKernelEntryPointAttr *SKEPAttr = nullptr; + for (auto SAI = FD->specific_attr_begin<SYCLKernelEntryPointAttr>(); + SAI != FD->specific_attr_end<SYCLKernelEntryPointAttr>(); + ++SAI) { + if (!SKEPAttr) { + SKEPAttr = *SAI; + continue; + } + if (!getASTContext().hasSameType(SAI->getKernelName(), + SKEPAttr->getKernelName())) { + Diag(SAI->getLocation(), diag::err_sycl_entry_point_invalid_redeclaration) + << SAI->getKernelName() << SKEPAttr->getKernelName(); + Diag(SKEPAttr->getLocation(), diag::note_previous_attribute); + } else { + Diag(SAI->getLocation(), + diag::warn_sycl_entry_point_redundant_declaration); + Diag(SKEPAttr->getLocation(), diag::note_previous_attribute); + } + } + assert(SKEPAttr && "Missing sycl_kernel_entry_point attribute"); + + // Ensure the kernel name type is valid. + if (!SKEPAttr->getKernelName()->isDependentType()) { + CheckSYCLKernelName(SemaRef, SKEPAttr->getLocation(), + SKEPAttr->getKernelName()); + } + + // Ensure that an attribute present on the previous declaration + // matches the one on this declaration. + FunctionDecl *PrevFD = FD->getPreviousDecl(); + if (PrevFD && !PrevFD->isInvalidDecl()) { + const auto *PrevSKEPAttr = PrevFD->getAttr<SYCLKernelEntryPointAttr>(); + if (PrevSKEPAttr) { + if (!getASTContext().hasSameType(SKEPAttr->getKernelName(), + PrevSKEPAttr->getKernelName())) { + Diag(SKEPAttr->getLocation(), + diag::err_sycl_entry_point_invalid_redeclaration) + << SKEPAttr->getKernelName() << PrevSKEPAttr->getKernelName(); + Diag(PrevSKEPAttr->getLocation(), diag::note_previous_decl) + << PrevFD;; + } + } + } + + if (auto *MD = dyn_cast<CXXMethodDecl>(FD)) { + if (!MD->isStatic()) { + Diag(SKEPAttr->getLocation(), diag::err_sycl_entry_point_invalid) + << /*non-static member function*/0; + } + } + if (FD->isVariadic()) { + Diag(SKEPAttr->getLocation(), diag::err_sycl_entry_point_invalid) + << /*variadic function*/1; + } + if (FD->isConsteval()) { + Diag(SKEPAttr->getLocation(), diag::err_sycl_entry_point_invalid) + << /*consteval function*/5; + } else if (FD->isConstexpr()) { + Diag(SKEPAttr->getLocation(), diag::err_sycl_entry_point_invalid) + << /*constexpr function*/4; + } + if (FD->isNoReturn()) { + Diag(SKEPAttr->getLocation(), diag::err_sycl_entry_point_invalid) + << /*noreturn function*/6; + } + + if (!FD->getReturnType()->isVoidType()) { + Diag(SKEPAttr->getLocation(), diag::err_sycl_entry_point_return_type); + } + + if (!FD->isInvalidDecl() && !FD->isTemplated()) { + const SYCLKernelInfo *SKI = + getASTContext().findSYCLKernelInfo(SKEPAttr->getKernelName()); + if (SKI) { + if (!declaresSameEntity(FD, SKI->getKernelEntryPointDecl())) { + // FIXME: This diagnostic should include the origin of the kernel + // FIXME: names; not just the locations of the conflicting declarations. + Diag(FD->getLocation(), diag::err_sycl_kernel_name_conflict); + Diag(SKI->getKernelEntryPointDecl()->getLocation(), + diag::note_previous_declaration); + } + } else { + getASTContext().registerSYCLEntryPointFunction(FD); + } + } +} diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 5e7a3c8484c88f..59e24f885eee4a 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -1550,6 +1550,8 @@ NamedDecl *Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D, IdResolver.AddDecl(Param); } + ProcessDeclAttributes(S, Param, D); + // C++0x [temp.param]p9: // A default template-argument may be specified for any kind of // template-parameter that is not a template parameter pack. diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp index 719bc0d06f5b11..ac5dd7fd16303e 100644 --- a/clang/lib/Serialization/ASTReaderDecl.cpp +++ b/clang/lib/Serialization/ASTReaderDecl.cpp @@ -1134,8 +1134,19 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) { // the presence of a sycl_kernel_entry_point attribute, register it so that // associated metadata is recreated. if (FD->hasAttr<SYCLKernelEntryPointAttr>()) { + const auto *SKEPAttr = FD->getAttr<SYCLKernelEntryPointAttr>(); ASTContext &C = Reader.getContext(); - C.registerSYCLEntryPointFunction(FD); + const SYCLKernelInfo *SKI = + C.findSYCLKernelInfo(SKEPAttr->getKernelName()); + if (SKI) { + if (!declaresSameEntity(FD, SKI->getKernelEntryPointDecl())) { + Reader.Diag(FD->getLocation(), diag::err_sycl_kernel_name_conflict); + Reader.Diag(SKI->getKernelEntryPointDecl()->getLocation(), + diag::note_previous_declaration); + } + } else { + C.registerSYCLEntryPointFunction(FD); + } } } diff --git a/clang/test/ASTSYCL/ast-dump-sycl-kernel-entry-point.cpp b/clang/test/ASTSYCL/ast-dump-sycl-kernel-entry-point.cpp index c351f3b7d03eab..0189cf0402d3a3 100644 --- a/clang/test/ASTSYCL/ast-dump-sycl-kernel-entry-point.cpp +++ b/clang/test/ASTSYCL/ast-dump-sycl-kernel-entry-point.cpp @@ -107,14 +107,29 @@ void skep5<KN<5,2>>(long) { // CHECK: | |-TemplateArgument type 'long' // CHECK: | `-SYCLKernelEntryPointAttr {{.*}} KN<5, 2> +// FIXME: C++23 [temp.expl.spec]p12 states: +// FIXME: ... Similarly, attributes appearing in the declaration of a template +// FIXME: have no effect on an explicit specialization of that template. +// FIXME: Clang currently instantiates a function template specialization from +// FIXME: the function template declaration and links it as a previous +// FIXME: declaration of an explicit specialization. The instantiated +// FIXME: declaration includes attributes instantiated from the function +// FIXME: template declaration. When the instantiated declaration and the +// FIXME: explicit specialization both specify a sycl_kernel_entry_point +// FIXME: attribute with different kernel name types, a spurious diagnostic +// FIXME: is issued. The following test case is incorrectly diagnosed as +// FIXME: having conflicting kernel name types (KN<5,3> vs the incorrectly +// FIXME: inherited KN<5,-1>). +#if 0 template<> [[clang::sycl_kernel_entry_point(KN<5,3>)]] void skep5<KN<5,-1>>(long long) { } -// CHECK: |-FunctionDecl {{.*}} prev {{.*}} skep5 'void (long long)' explicit_specialization -// CHECK-NEXT: | |-TemplateArgument type 'KN<5, -1>' -// CHECK: | |-TemplateArgument type 'long long' -// CHECK: | `-SYCLKernelEntryPointAttr {{.*}} KN<5, 3> +// FIXME-CHECK: |-FunctionDecl {{.*}} prev {{.*}} skep5 'void (long long)' explicit_specialization +// FIXME-CHECK-NEXT: | |-TemplateArgument type 'KN<5, -1>' +// FIXME-CHECK: | |-TemplateArgument type 'long long' +// FIXME-CHECK: | `-SYCLKernelEntryPointAttr {{.*}} KN<5, 3> +#endif template void skep5<KN<5,4>>(int); // Checks are located with the primary template declaration above. diff --git a/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-appertainment.cpp b/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-appertainment.cpp new file mode 100644 index 00000000000000..5f638061a96408 --- /dev/null +++ b/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-appertainment.cpp @@ -0,0 +1,255 @@ +// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++17 -fsyntax-only -fsycl-is-device -verify %s +// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++20 -fsyntax-only -fsycl-is-device -verify %s + +// These tests validate appertainment for the sycl_kernel_entry_point attribute. + +#if __cplusplus >= 202002L +// Mock coroutine support. +namespace std { + +template<typename Promise = void> +struct coroutine_handle { + template<typename T> + coroutine_handle(const coroutine_handle<T>&); + static coroutine_handle from_address(void *addr); +}; + +template<typename R, typename... Args> +struct coroutine_traits { + struct suspend_never { + bool await_ready() const noexcept; + void await_suspend(std::coroutine_handle<>) const noexcept; + void await_resume() const noexcept; + }; + struct promise_type { + void get_return_object() noexcept; + suspend_never initial_suspend() const noexcept; + suspend_never final_suspend() const noexcept; + void return_void() noexcept; + void unhandled_exception() noexcept; + }; +}; + +} +#endif + +// A unique kernel name type is required for each declared kernel entry point. +template<int, int = 0> struct KN; + + +//////////////////////////////////////////////////////////////////////////////// +// Valid declarations. +//////////////////////////////////////////////////////////////////////////////// + +// Function declaration with GNU attribute spelling +__attribute__((sycl_kernel_entry_point(KN<1>))) +void ok1(); + +// Function declaration with Clang attribute spelling. +[[clang::sycl_kernel_entry_point(KN<2>)]] +void ok2(); + +// Function definition. +[[clang::sycl_kernel_entry_point(KN<3>)]] +void ok3() {} + +// Function template definition. +template<typename KNT, typename T> +[[clang::sycl_kernel_entry_point(KNT)]] +void ok4(T) {} + +// Function template explicit specialization. +template<> +[[clang::sycl_kernel_entry_point(KN<4,1>)]] +void ok4<KN<4,1>>(int) {} + +// Function template explicit instantiation. +template void ok4<KN<4,2>, long>(long); + +namespace NS { +// Function declaration at namespace scope. +[[clang::sycl_kernel_entry_point(KN<5>)]] +void ok5(); +} + +struct S6 { + // Static member function declaration. + [[clang::sycl_kernel_entry_point(KN<6>)]] + static void ok6(); +}; + +// Dependent friend function. +template<typename KNT> +struct S7 { + [[clang::sycl_kernel_entry_point(KNT)]] + friend void ok7(S7) {} +}; +void test_ok7() { + ok7(S7<KN<7>>{}); +} + +// The sycl_kernel_entry_point attribute must match across declarations and +// cannot be added for the first time after a definition. +[[clang::sycl_kernel_entry_point(KN<8>)]] +void ok8(); +[[clang::sycl_kernel_entry_point(KN<8>)]] +void ok8(); +[[clang::sycl_kernel_entry_point(KN<9>)]] +void ok9(); +void ok9() {} +void ok10(); +[[clang::sycl_kernel_entry_point(KN<10>)]] +void ok10() {} + +using VOID = void; +[[clang::sycl_kernel_entry_point(KN<11>)]] +VOID ok11(); +[[clang::sycl_kernel_entry_point(KN<12>)]] +const void ok12(); + + +//////////////////////////////////////////////////////////////////////////////// +// Invalid declarations. +//////////////////////////////////////////////////////////////////////////////// + +// The sycl_kernel_entry_point attribute cannot appertain to main() because +// main() has a non-void return type. However, if the requirement for a void +// return type were to be relaxed or if an allowance was made for main() to +// return void (as gcc allows in some modes and as has been proposed to WG21 +// on occassion), main() still can't function as a SYCL kernel entry point, +// so this test ensures such attempted uses of the attribute are rejected. +struct Smain; +// expected-error@+1 {{'sycl_kernel_entry_point' attribute only applies to functions with a 'void' return type}} +[[clang::sycl_kernel_entry_point(Smain)]] +int main(); + +template<int> struct BADKN; + +struct B1 { + // Non-static data member declaration. + // expected-error@+1 {{'sycl_kernel_entry_point' attribute only applies to functions}} + [[clang::sycl_kernel_entry_point(BADKN<1>)]] + int bad1; +}; + +struct B2 { + // Static data member declaration. + // expected-error@+1 {{'sycl_kernel_entry_point' attribute only applies to functions}} + [[clang::sycl_kernel_entry_point(BADKN<2>)]] + static int bad2; +}; + +struct B3 { + // Non-static member function declaration. + // expected-error@+1 {{'sycl_kernel_entry_point' attribute cannot be applied to a non-static member function}} + [[clang::sycl_kernel_entry_point(BADKN<3>)]] + void bad3(); +}; + +// expected-error@+1 {{'sycl_kernel_entry_point' attribute only applies to functions}} +namespace bad4 [[clang::sycl_kernel_entry_point(BADKN<4>)]] {} + +#if __cplusplus >= 202002L +// expected-error@+2 {{'sycl_kernel_entry_point' attribute only applies to functions}} +template<typename> +concept bad5 [[clang::sycl_kernel_entry_point(BADKN<5>)]] = true; +#endif + +// Type alias declarations. +// expected-error@+1 {{'sycl_kernel_entry_point' attribute only applies to functions}} +typedef void bad6 [[clang::sycl_kernel_entry_point(BADKN<6>)]] (); +// expected-error@+1 {{'sycl_kernel_entry_point' attribute only applies to functions}} +using bad7 [[clang::sycl_kernel_entry_point(BADKN<7>)]] = void(); +// expected-error@+1 {{'sycl_kernel_entry_point' attribute only applies to functions}} +using bad8 [[clang::sycl_kernel_entry_point(BADKN<8>)]] = int; +// expected-error@+1 {{'sycl_kernel_entry_point' attribute cannot be applied to types}} +using bad9 = int [[clang::sycl_kernel_entry_point(BADKN<9>)]]; +// expected-error@+1 {{'sycl_kernel_entry_point' attribute cannot be applied to types}} +using bad10 = int() [[clang::sycl_kernel_entry_point(BADKN<10>)]]; + +// Variable declaration. +// expected-error@+1 {{'sycl_kernel_entry_point' attribute only applies to functions}} +[[clang::sycl_kernel_entry_point(BADKN<11>)]] +int bad11; + +// Class declaration. +// expected-error@+1 {{'sycl_kernel_entry_point' attribute only applies to functions}} +struct [[clang::sycl_kernel_entry_point(BADKN<12>)]] bad12; + +// Enumeration declaration. +// expected-error@+1 {{'sycl_kernel_entry_point' attribute only applies to functions}} +enum [[clang::sycl_kernel_entry_point(BADKN<13>)]] bad13 {}; + +// Enumerator. +// expected-error@+2 {{'sycl_kernel_entry_point' attribute only applies to functions}} +enum { + bad14 [[clang::sycl_kernel_entry_point(BADKN<14>)]] +}; + +// Attribute added after the definition. +// expected-error@+3 {{'sycl_kernel_entry_point' attribute cannot be added to a function after the function is defined}} +// expected-note@+1 {{previous definition is here}} +void bad15() {} +[[clang::sycl_kernel_entry_point(BADKN<15>)]] +void bad15(); + +// The function must return void. +// expected-error@+1 {{'sycl_kernel_entry_point' attribute only applies to functions with a 'void' return type}} +[[clang::sycl_kernel_entry_point(BADKN<16>)]] +int bad16(); + +// Function parameters. +// expected-error@+1 {{'sycl_kernel_entry_point' attribute only applies to functions}} +void bad17(void (fp [[clang::sycl_kernel_entry_point(BADKN<17>)]])()); + +// Function template parameters. +// expected-error@+1 {{'sycl_kernel_entry_point' attribute only applies to functions}} +template<void (fp [[clang::sycl_kernel_entry_point(BADKN<18>)]])()> +void bad18(); + +#if __cplusplus >= 202002L +// expected-error@+1 {{'sycl_kernel_entry_point' attribute cannot be applied to a coroutine function}} +[[clang::sycl_kernel_entry_point(BADKN<19>)]] +void bad19() { + co_return; +} +#endif + +struct B20 { + // expected-error@+1 {{'sycl_kernel_entry_point' attribute cannot be applied to a non-static member function}} + [[clang::sycl_kernel_entry_point(BADKN<20>)]] + B20(); +}; + +struct B21 { + // expected-error@+1 {{'sycl_kernel_entry_point' attribute cannot be applied to a non-static member function}} + [[clang::sycl_kernel_entry_point(BADKN<21>)]] + ~B21(); +}; + +// expected-error@+1 {{'sycl_kernel_entry_point' attribute cannot be applied to a variadic function}} +[[clang::sycl_kernel_entry_point(BADKN<22>)]] +void bad22(...); + +// expected-error@+1 {{'sycl_kernel_entry_point' attribute cannot be applied to a deleted function}} +[[clang::sycl_kernel_entry_point(BADKN<23>)]] +void bad23() = delete; + +// expected-error@+1 {{'sycl_kernel_entry_point' attribute cannot be applied to a constexpr function}} +[[clang::sycl_kernel_entry_point(BADKN<24>)]] +constexpr void bad24() {} + +#if __cplusplus >= 202002L +// expected-error@+1 {{'sycl_kernel_entry_point' attribute cannot be applied to a consteval function}} +[[clang::sycl_kernel_entry_point(BADKN<25>)]] +consteval void bad25() {} +#endif + +// expected-error@+1 {{'sycl_kernel_entry_point' attribute cannot be applied to a noreturn function}} +[[clang::sycl_kernel_entry_point(BADKN<26>)]] +[[noreturn]] void bad26(); + +// expected-error@+3 {{attribute 'target' multiversioning cannot be combined with attribute 'sycl_kernel_entry_point'}} +__attribute__((target("avx"))) void bad27(); +[[clang::sycl_kernel_entry_point(BADKN<27>)]] +__attribute__((target("sse4.2"))) void bad27(); diff --git a/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-grammar.cpp b/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-grammar.cpp index c63d241163e618..14b5d2746631d6 100644 --- a/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-grammar.cpp +++ b/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-grammar.cpp @@ -120,18 +120,3 @@ template<typename> concept C = true; // expected-error@+1 {{expected a type}} [[clang::sycl_kernel_entry_point(C<int>)]] void bad11(); #endif - -struct B12; // #B12-decl -// FIXME: C++23 [temp.expl.spec]p12 states: -// FIXME: ... Similarly, attributes appearing in the declaration of a template -// FIXME: have no effect on an explicit specialization of that template. -// FIXME: Clang currently instantiates and propagates attributes from a function -// FIXME: template to its explicit specializations resulting in the following -// FIXME: spurious error. -// expected-error@+4 {{incomplete type 'B12' named in nested name specifier}} -// expected-note@+5 {{in instantiation of function template specialization 'bad12<B12>' requested here}} -// expected-note@#B12-decl {{forward declaration of 'B12'}} -template<typename T> -[[clang::sycl_kernel_entry_point(typename T::not_found)]] void bad12() {} -template<> -void bad12<B12>() {} diff --git a/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-kernel-name-module.cpp b/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-kernel-name-module.cpp new file mode 100644 index 00000000000000..83c3e5ca267ab2 --- /dev/null +++ b/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-kernel-name-module.cpp @@ -0,0 +1,104 @@ +// Test that SYCL kernel name conflicts that occur across module boundaries are +// properly diagnosed and that declarations are properly merged so that spurious +// conflicts are not reported. + +// RUN: rm -rf %t +// RUN: split-file %s %t +// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t \ +// RUN: -std=c++17 -fsycl-is-host %t/test.cpp -verify +// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t \ +// RUN: -std=c++17 -fsycl-is-device %t/test.cpp -verify + +#--- module.modulemap +module M1 { header "m1.h" } +module M2 { header "m2.h" } + + +#--- common.h +template<int> struct KN; + +[[clang::sycl_kernel_entry_point(KN<1>)]] +void common_test1() {} + +template<typename T> +[[clang::sycl_kernel_entry_point(T)]] +void common_test2() {} +template void common_test2<KN<2>>(); + + +#--- m1.h +#include "common.h" + +[[clang::sycl_kernel_entry_point(KN<3>)]] +void m1_test3() {} // << expected previous declaration note here. + +template<typename T> +[[clang::sycl_kernel_entry_point(T)]] +void m1_test4() {} // << expected previous declaration note here. +template void m1_test4<KN<4>>(); + +[[clang::sycl_kernel_entry_point(KN<5>)]] +void m1_test5() {} // << expected previous declaration note here. + +template<typename T> +[[clang::sycl_kernel_entry_point(T)]] +void m1_test6() {} // << expected previous declaration note here. +template void m1_test6<KN<6>>(); + + +#--- m2.h +#include "common.h" + +[[clang::sycl_kernel_entry_point(KN<3>)]] +void m2_test3() {} // << expected kernel name conflict here. + +template<typename T> +[[clang::sycl_kernel_entry_point(T)]] +void m2_test4() {} // << expected kernel name conflict here. +template void m2_test4<KN<4>>(); + +[[clang::sycl_kernel_entry_point(KN<7>)]] +void m2_test7() {} // << expected previous declaration note here. + +template<typename T> +[[clang::sycl_kernel_entry_point(T)]] +void m2_test8() {} // << expected previous declaration note here. +template void m2_test8<KN<8>>(); + + +#--- test.cpp +#include "m1.h" +#include "m2.h" + +// Expected diagnostics for m1_test3() and m2_test3(): +// expected-error@m2.h:4 {{'sycl_kernel_entry_point' kernel name argument conflicts with a previous declaration}} +// expected-note@m1.h:12 {{previous declaration is here}} + +// Expected diagnostics for m1_test4<KN<4>>() and m2_test4<KN<4>>(): +// expected-error@m2.h:8 {{'sycl_kernel_entry_point' kernel name argument conflicts with a previous declaration}} +// expected-note@m1.h:16 {{previous declaration is here}} + +// expected-error@+3 {{'sycl_kernel_entry_point' kernel name argument conflicts with a previous declaration}} +// expected-note@m1.h:4 {{previous declaration is here}} +[[clang::sycl_kernel_entry_point(KN<5>)]] +void test5() {} + +// expected-error@+3 {{'sycl_kernel_entry_point' kernel name argument conflicts with a previous declaration}} +// expected-note@m1.h:8 {{previous declaration is here}} +[[clang::sycl_kernel_entry_point(KN<6>)]] +void test6() {} + +// expected-error@+3 {{'sycl_kernel_entry_point' kernel name argument conflicts with a previous declaration}} +// expected-note@m2.h:12 {{previous declaration is here}} +[[clang::sycl_kernel_entry_point(KN<7>)]] +void test7() {} + +// expected-error@+3 {{'sycl_kernel_entry_point' kernel name argument conflicts with a previous declaration}} +// expected-note@m2.h:16 {{previous declaration is here}} +[[clang::sycl_kernel_entry_point(KN<8>)]] +void test8() {} + +void f() { + common_test1(); + common_test2<KN<2>>(); +} diff --git a/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-kernel-name-pch.cpp b/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-kernel-name-pch.cpp new file mode 100644 index 00000000000000..0814d898d1c0e0 --- /dev/null +++ b/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-kernel-name-pch.cpp @@ -0,0 +1,36 @@ +// Test that SYCL kernel name conflicts that occur across PCH boundaries are +// properly diagnosed. + +// RUN: rm -rf %t +// RUN: split-file %s %t +// RUN: %clang_cc1 -std=c++17 -fsycl-is-host -emit-pch -x c++-header \ +// RUN: %t/pch.h -o %t/pch.h.host.pch +// RUN: %clang_cc1 -std=c++17 -fsycl-is-host -verify \ +// RUN: -include-pch %t/pch.h.host.pch %t/test.cpp +// RUN: %clang_cc1 -std=c++17 -fsycl-is-device -emit-pch -x c++-header \ +// RUN: %t/pch.h -o %t/pch.h.device.pch +// RUN: %clang_cc1 -std=c++17 -fsycl-is-device -verify \ +// RUN: -include-pch %t/pch.h.device.pch %t/test.cpp + +#--- pch.h +template<int> struct KN; + +[[clang::sycl_kernel_entry_point(KN<1>)]] +void pch_test1() {} // << expected previous declaration note here. + +template<typename T> +[[clang::sycl_kernel_entry_point(T)]] +void pch_test2() {} // << expected previous declaration note here. +template void pch_test2<KN<2>>(); + + +#--- test.cpp +// expected-error@+3 {{'sycl_kernel_entry_point' kernel name argument conflicts with a previous declaration}} +// expected-note@pch.h:4 {{previous declaration is here}} +[[clang::sycl_kernel_entry_point(KN<1>)]] +void test1() {} + +// expected-error@+3 {{'sycl_kernel_entry_point' kernel name argument conflicts with a previous declaration}} +// expected-note@pch.h:8 {{previous declaration is here}} +[[clang::sycl_kernel_entry_point(KN<2>)]] +void test2() {} diff --git a/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-kernel-name.cpp b/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-kernel-name.cpp new file mode 100644 index 00000000000000..989aa5ba06f893 --- /dev/null +++ b/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-kernel-name.cpp @@ -0,0 +1,87 @@ +// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++17 -fsyntax-only -fsycl-is-device -verify %s +// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++20 -fsyntax-only -fsycl-is-device -verify %s + +// These tests validate that the kernel name type argument provided to the +// sycl_kernel_entry_point attribute meets the requirements of a SYCL kernel +// name as described in section 5.2, "Naming of kernels", of the SYCL 2020 +// specification. + +struct S1; +// expected-warning@+3 {{redundant 'sycl_kernel_entry_point' attribute}} +// expected-note@+1 {{previous attribute is here}} +[[clang::sycl_kernel_entry_point(S1), + clang::sycl_kernel_entry_point(S1)]] +void ok1(); + +// expected-error@+1 {{'int' is not a valid SYCL kernel name type; a class type is required}} +[[clang::sycl_kernel_entry_point(int)]] void bad2(); + +// expected-error@+1 {{'int ()' is not a valid SYCL kernel name type; a class type is required}} +[[clang::sycl_kernel_entry_point(int())]] void bad3(); + +// expected-error@+1 {{'int (*)()' is not a valid SYCL kernel name type; a class type is required}} +[[clang::sycl_kernel_entry_point(int(*)())]] void bad4(); + +// expected-error@+1 {{'int (&)()' is not a valid SYCL kernel name type; a class type is required}} +[[clang::sycl_kernel_entry_point(int(&)())]] void bad5(); + +// expected-error@+1 {{'decltype(nullptr)' (aka 'std::nullptr_t') is not a valid SYCL kernel name type; a class type is required}} +[[clang::sycl_kernel_entry_point(decltype(nullptr))]] void bad6(); + +union U7; // #U7-decl +// expected-error@+2 {{'U7' is not a valid SYCL kernel name type; a class type is required}} +// expected-note@#U7-decl {{'U7' declared here}} +[[clang::sycl_kernel_entry_point(U7)]] void bad7(); + +enum E8 {}; // #E8-decl +// expected-error@+2 {{'E8' is not a valid SYCL kernel name type; a class type is required}} +// expected-note@#E8-decl {{'E8' declared here}} +[[clang::sycl_kernel_entry_point(E8)]] void bad8(); + +enum E9 : int; // #E9-decl +// expected-error@+2 {{'E9' is not a valid SYCL kernel name type; a class type is required}} +// expected-note@#E9-decl {{'E9' declared here}} +[[clang::sycl_kernel_entry_point(E9)]] void bad9(); + +struct B10 { + struct MS; +}; +// FIXME-expected-error@+1 {{'sycl_kernel_entry_point' attribute argument must be a forward declarable class type}} +[[clang::sycl_kernel_entry_point(B10::MS)]] void bad10(); + +struct B11 { + struct MS; +}; +// FIXME-expected-error@+3 {{'sycl_kernel_entry_point' attribute argument must be a forward declarable class type}} +template<typename T> +[[clang::sycl_kernel_entry_point(typename T::MS)]] void bad11() {} +template void bad11<B11>(); + +template<typename T> +[[clang::sycl_kernel_entry_point(T)]] void bad12(); +void f12() { + // FIXME-expected-error@+2 {{'sycl_kernel_entry_point' attribute argument must be a forward declarable class type}} + struct LS; + bad12<LS>(); +} + +struct B13_1; +struct B13_2; +// expected-error@+3 {{'sycl_kernel_entry_point' kernel name argument does not match prior declaration: 'B13_2' vs 'B13_1'}} +// expected-note@+1 {{'bad13' declared here}} +[[clang::sycl_kernel_entry_point(B13_1)]] void bad13(); +[[clang::sycl_kernel_entry_point(B13_2)]] void bad13() {} + +struct B14_1; +struct B14_2; +// expected-error@+3 {{'sycl_kernel_entry_point' kernel name argument does not match prior declaration: 'B14_2' vs 'B14_1'}} +// expected-note@+1 {{previous attribute is here}} +[[clang::sycl_kernel_entry_point(B14_1), + clang::sycl_kernel_entry_point(B14_2)]] +void bad14(); + +struct B15; +// expected-error@+3 {{'sycl_kernel_entry_point' kernel name argument conflicts with a previous declaration}} +// expected-note@+1 {{previous declaration is here}} +[[clang::sycl_kernel_entry_point(B15)]] void bad15_1(); +[[clang::sycl_kernel_entry_point(B15)]] void bad15_2(); diff --git a/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-sfinae.cpp b/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-sfinae.cpp new file mode 100644 index 00000000000000..872ecbd4844aad --- /dev/null +++ b/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-sfinae.cpp @@ -0,0 +1,65 @@ +// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++17 -fsyntax-only -fsycl-is-device -verify %s +// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++20 -fsyntax-only -fsycl-is-device -verify %s + +// These tests are intended to validate that a sycl_kernel_entry_point attribute +// appearing in the declaration of a function template does not affect overload +// resolution or cause spurious errors during overload resolution due to either +// a substitution failure in the attribute argument or a semantic check of the +// attribute during instantiation of a specialization unless that specialization +// is selected by overload resolution. + +// FIXME: C++23 [temp.expl.spec]p12 states: +// FIXME: ... Similarly, attributes appearing in the declaration of a template +// FIXME: have no effect on an explicit specialization of that template. +// FIXME: Clang currently instantiates and propagates attributes from a function +// FIXME: template to its explicit specializations resulting in the following +// FIXME: spurious error. +struct S1; // #S1-decl +// expected-error@+4 {{incomplete type 'S1' named in nested name specifier}} +// expected-note@+5 {{in instantiation of function template specialization 'ok1<S1>' requested here}} +// expected-note@#S1-decl {{forward declaration of 'S1'}} +template<typename T> +[[clang::sycl_kernel_entry_point(typename T::invalid)]] void ok1() {} +template<> +void ok1<S1>() {} +void test_ok1() { + // ok1<S1>() is not a call to a SYCL kernel entry point function. + ok1<S1>(); +} + +// FIXME: The sycl_kernel_entry_point attribute should not be instantiated +// FIXME: until after overload resolution has completed. +struct S2; // #S2-decl +// expected-error@+6 {{incomplete type 'S2' named in nested name specifier}} +// expected-note@+10 {{in instantiation of function template specialization 'ok2<S2>' requested here}} +// expected-note@#S2-decl {{forward declaration of 'S2'}} +template<typename T> +[[clang::sycl_kernel_entry_point(T)]] void ok2(int) {} +template<typename T> +[[clang::sycl_kernel_entry_point(typename T::invalid)]] void ok2(long) {} +void test_ok2() { + // ok2(int) is a better match and is therefore selected by overload + // resolution; the attempted instantiation of ok2(long) should not produce + // an error for the substitution failure into the attribute argument. + ok2<S2>(2); +} + +// FIXME: The sycl_kernel_entry_point attribute should not be instantiated +// FIXME: until after overload resolution has completed. +struct S3; +struct Select3 { + using bad_type = int; + using good_type = S3; +}; +// expected-error@+5 {{'typename Select3::bad_type' (aka 'int') is not a valid SYCL kernel name type; a class type is required}} +// expected-note@+9 {{in instantiation of function template specialization 'ok3<Select3>' requested here}} +template<typename T> +[[clang::sycl_kernel_entry_point(typename T::good_type)]] void ok3(int) {} +template<typename T> +[[clang::sycl_kernel_entry_point(typename T::bad_type)]] void ok3(long) {} +void test_ok3() { + // ok3(int) is a better match and is therefore selected by overload + // resolution; the attempted instantiation of ok3(long) should not produce + // an error for the invalid kernel name provided as the attribute argument. + ok3<Select3>(2); +} >From 0b7f6bf0a98f826506ff1ffdd9d0750a9f5a0fcb Mon Sep 17 00:00:00 2001 From: Tom Honermann <tom.honerm...@intel.com> Date: Tue, 17 Dec 2024 15:10:51 -0800 Subject: [PATCH 2/8] Squash; Fix clang-format complaints. --- clang/lib/Sema/SemaDecl.cpp | 8 ++++---- clang/lib/Sema/SemaSYCL.cpp | 19 ++++++++----------- clang/lib/Serialization/ASTReaderDecl.cpp | 5 ++--- 3 files changed, 14 insertions(+), 18 deletions(-) diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index aea8bb112c0271..a68dcfe5c25cf9 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -52,8 +52,8 @@ #include "clang/Sema/SemaOpenMP.h" #include "clang/Sema/SemaPPC.h" #include "clang/Sema/SemaRISCV.h" -#include "clang/Sema/SemaSwift.h" #include "clang/Sema/SemaSYCL.h" +#include "clang/Sema/SemaSwift.h" #include "clang/Sema/SemaWasm.h" #include "clang/Sema/Template.h" #include "llvm/ADT/STLForwardCompat.h" @@ -15994,15 +15994,15 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, if (FD->isDeleted()) { Diag(FD->getAttr<SYCLKernelEntryPointAttr>()->getLocation(), diag::err_sycl_entry_point_invalid) - << /*deleted function*/2; + << /*deleted function*/ 2; } else if (FD->isDefaulted()) { Diag(FD->getAttr<SYCLKernelEntryPointAttr>()->getLocation(), diag::err_sycl_entry_point_invalid) - << /*defaulted function*/3; + << /*defaulted function*/ 3; } else if (FSI->isCoroutine()) { Diag(FD->getAttr<SYCLKernelEntryPointAttr>()->getLocation(), diag::err_sycl_entry_point_invalid) - << /*coroutine*/7; + << /*coroutine*/ 7; } } diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp index 04ab8c28e14108..3ae4fcd6e99f9b 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -235,8 +235,7 @@ static bool CheckSYCLKernelName(Sema &S, SourceLocation Loc, S.Diag(Loc, diag::warn_sycl_kernel_name_not_a_class_type) << KernelName; SourceLocation DeclTypeLoc = SourceLocationForType(KernelName); if (DeclTypeLoc.isValid()) - S.Diag(DeclTypeLoc, diag::note_entity_declared_at) - << KernelName; + S.Diag(DeclTypeLoc, diag::note_entity_declared_at) << KernelName; return true; } @@ -248,8 +247,7 @@ void SemaSYCL::CheckSYCLEntryPointFunctionDecl(FunctionDecl *FD) { // and warn about any redundant ones. const SYCLKernelEntryPointAttr *SKEPAttr = nullptr; for (auto SAI = FD->specific_attr_begin<SYCLKernelEntryPointAttr>(); - SAI != FD->specific_attr_end<SYCLKernelEntryPointAttr>(); - ++SAI) { + SAI != FD->specific_attr_end<SYCLKernelEntryPointAttr>(); ++SAI) { if (!SKEPAttr) { SKEPAttr = *SAI; continue; @@ -284,8 +282,7 @@ void SemaSYCL::CheckSYCLEntryPointFunctionDecl(FunctionDecl *FD) { Diag(SKEPAttr->getLocation(), diag::err_sycl_entry_point_invalid_redeclaration) << SKEPAttr->getKernelName() << PrevSKEPAttr->getKernelName(); - Diag(PrevSKEPAttr->getLocation(), diag::note_previous_decl) - << PrevFD;; + Diag(PrevSKEPAttr->getLocation(), diag::note_previous_decl) << PrevFD; } } } @@ -293,23 +290,23 @@ void SemaSYCL::CheckSYCLEntryPointFunctionDecl(FunctionDecl *FD) { if (auto *MD = dyn_cast<CXXMethodDecl>(FD)) { if (!MD->isStatic()) { Diag(SKEPAttr->getLocation(), diag::err_sycl_entry_point_invalid) - << /*non-static member function*/0; + << /*non-static member function*/ 0; } } if (FD->isVariadic()) { Diag(SKEPAttr->getLocation(), diag::err_sycl_entry_point_invalid) - << /*variadic function*/1; + << /*variadic function*/ 1; } if (FD->isConsteval()) { Diag(SKEPAttr->getLocation(), diag::err_sycl_entry_point_invalid) - << /*consteval function*/5; + << /*consteval function*/ 5; } else if (FD->isConstexpr()) { Diag(SKEPAttr->getLocation(), diag::err_sycl_entry_point_invalid) - << /*constexpr function*/4; + << /*constexpr function*/ 4; } if (FD->isNoReturn()) { Diag(SKEPAttr->getLocation(), diag::err_sycl_entry_point_invalid) - << /*noreturn function*/6; + << /*noreturn function*/ 6; } if (!FD->getReturnType()->isVoidType()) { diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp index ac5dd7fd16303e..e65983f2013730 100644 --- a/clang/lib/Serialization/ASTReaderDecl.cpp +++ b/clang/lib/Serialization/ASTReaderDecl.cpp @@ -1136,13 +1136,12 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) { if (FD->hasAttr<SYCLKernelEntryPointAttr>()) { const auto *SKEPAttr = FD->getAttr<SYCLKernelEntryPointAttr>(); ASTContext &C = Reader.getContext(); - const SYCLKernelInfo *SKI = - C.findSYCLKernelInfo(SKEPAttr->getKernelName()); + const SYCLKernelInfo *SKI = C.findSYCLKernelInfo(SKEPAttr->getKernelName()); if (SKI) { if (!declaresSameEntity(FD, SKI->getKernelEntryPointDecl())) { Reader.Diag(FD->getLocation(), diag::err_sycl_kernel_name_conflict); Reader.Diag(SKI->getKernelEntryPointDecl()->getLocation(), - diag::note_previous_declaration); + diag::note_previous_declaration); } } else { C.registerSYCLEntryPointFunction(FD); >From 0e89f398842841ccee29113aedc2437ee46eec62 Mon Sep 17 00:00:00 2001 From: Tom Honermann <tom.honerm...@intel.com> Date: Sun, 22 Dec 2024 20:58:16 -0800 Subject: [PATCH 3/8] Avoid attempted invalid registration of a SYCL kernel entry point function. Registration of a function as a SYCL kernel entry point when the kernel name provided for the `sycl_kernel_entry_point` attribute is invalid could lead to later errors (e.g., when generating the offload kernel) if the function declaration is not somehow marked as invalid so that such later attempts can be skipped. Most attributes, and the `sycl_kernel_entry_point` attribute specifically, should not affect overload resolution. Marking a function declaration as invalid with `setInvalidDecl()` causes overload resolution to skip the declaration, so use of it is not correct for marking function delcarations with invalid `sycl_kernel_entry_point` attributes. Dropping an invalid attribute with `dropAttr()` would similarly impact debugging and diagnostics generation and is therefore not a good option. This change allows instances of the `sycl_kernel_entry_point` attribute to be marked as invalid and adds checks to avoid SYCL kernel registration for functions with an attribute marked as invalid. Additional tests are provided to validate that the `sycl_kernel_entry_point` attribute is inherited and that non-dependent invalid uses of the attribute in dependent contexts are eagerly diagnosed without requiring an instantiation. --- clang/include/clang/Basic/Attr.td | 13 +++++++++- clang/lib/Sema/SemaDecl.cpp | 17 +++++++------ clang/lib/Sema/SemaSYCL.cpp | 24 +++++++++++++------ clang/lib/Serialization/ASTReaderDecl.cpp | 3 ++- ...cl-kernel-entry-point-attr-kernel-name.cpp | 15 ++++++++++++ 5 files changed, 56 insertions(+), 16 deletions(-) diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index 90d2a2056fe1ba..9f9dbaefb9351e 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -1516,11 +1516,22 @@ def SYCLKernel : InheritableAttr { def SYCLKernelEntryPoint : InheritableAttr { let Spellings = [Clang<"sycl_kernel_entry_point">]; - let Args = [TypeArgument<"KernelName">]; + let Args = [ + // KernelName is required and specifies the kernel name type. + TypeArgument<"KernelName">, + // InvalidAttr is a fake argument used to track whether the + // semantic requirements of the attribute have been satisified. + // A fake argument is used to enable serialization support. + DefaultBoolArgument<"Invalid", /*default=*/0, /*fake=*/1> + ]; let Subjects = SubjectList<[Function], ErrorDiag>; let TemplateDependent = 1; let LangOpts = [SYCLHost, SYCLDevice]; let Documentation = [SYCLKernelEntryPointDocs]; + let AdditionalMembers = [{ + void setInvalidAttr() { invalid = true; } + bool isInvalidAttr() const { return invalid; } + }]; } def SYCLSpecialClass: InheritableAttr { diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index a68dcfe5c25cf9..a94eaa6788cfc6 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -2924,7 +2924,7 @@ static void checkNewAttributesAfterDef(Sema &S, Decl *New, const Decl *Old) { AttrVec &NewAttributes = New->getAttrs(); for (unsigned I = 0, E = NewAttributes.size(); I != E;) { - const Attr *NewAttribute = NewAttributes[I]; + Attr *NewAttribute = NewAttributes[I]; if (isa<AliasAttr>(NewAttribute) || isa<IFuncAttr>(NewAttribute)) { if (FunctionDecl *FD = dyn_cast<FunctionDecl>(New)) { @@ -3026,6 +3026,7 @@ static void checkNewAttributesAfterDef(Sema &S, Decl *New, const Decl *Old) { S.Diag(NewAttribute->getLocation(), diag::err_sycl_entry_point_after_definition); S.Diag(Def->getLocation(), diag::note_previous_definition); + cast<SYCLKernelEntryPointAttr>(NewAttribute)->setInvalidAttr(); ++I; continue; } @@ -15991,18 +15992,20 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, // Diagnose invalid SYCL kernel entry point function declarations. if (FD && !FD->isInvalidDecl() && !FD->isTemplated() && FD->hasAttr<SYCLKernelEntryPointAttr>()) { + SYCLKernelEntryPointAttr *SKEPAttr = + FD->getAttr<SYCLKernelEntryPointAttr>(); if (FD->isDeleted()) { - Diag(FD->getAttr<SYCLKernelEntryPointAttr>()->getLocation(), - diag::err_sycl_entry_point_invalid) + Diag(SKEPAttr->getLocation(), diag::err_sycl_entry_point_invalid) << /*deleted function*/ 2; + SKEPAttr->setInvalidAttr(); } else if (FD->isDefaulted()) { - Diag(FD->getAttr<SYCLKernelEntryPointAttr>()->getLocation(), - diag::err_sycl_entry_point_invalid) + Diag(SKEPAttr->getLocation(), diag::err_sycl_entry_point_invalid) << /*defaulted function*/ 3; + SKEPAttr->setInvalidAttr(); } else if (FSI->isCoroutine()) { - Diag(FD->getAttr<SYCLKernelEntryPointAttr>()->getLocation(), - diag::err_sycl_entry_point_invalid) + Diag(SKEPAttr->getLocation(), diag::err_sycl_entry_point_invalid) << /*coroutine*/ 7; + SKEPAttr->setInvalidAttr(); } } diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp index 3ae4fcd6e99f9b..0ed9246b2319a3 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -245,7 +245,7 @@ static bool CheckSYCLKernelName(Sema &S, SourceLocation Loc, void SemaSYCL::CheckSYCLEntryPointFunctionDecl(FunctionDecl *FD) { // Ensure that all attributes present on the declaration are consistent // and warn about any redundant ones. - const SYCLKernelEntryPointAttr *SKEPAttr = nullptr; + SYCLKernelEntryPointAttr *SKEPAttr = nullptr; for (auto SAI = FD->specific_attr_begin<SYCLKernelEntryPointAttr>(); SAI != FD->specific_attr_end<SYCLKernelEntryPointAttr>(); ++SAI) { if (!SKEPAttr) { @@ -257,6 +257,7 @@ void SemaSYCL::CheckSYCLEntryPointFunctionDecl(FunctionDecl *FD) { Diag(SAI->getLocation(), diag::err_sycl_entry_point_invalid_redeclaration) << SAI->getKernelName() << SKEPAttr->getKernelName(); Diag(SKEPAttr->getLocation(), diag::note_previous_attribute); + SAI->setInvalidAttr(); } else { Diag(SAI->getLocation(), diag::warn_sycl_entry_point_redundant_declaration); @@ -266,23 +267,24 @@ void SemaSYCL::CheckSYCLEntryPointFunctionDecl(FunctionDecl *FD) { assert(SKEPAttr && "Missing sycl_kernel_entry_point attribute"); // Ensure the kernel name type is valid. - if (!SKEPAttr->getKernelName()->isDependentType()) { - CheckSYCLKernelName(SemaRef, SKEPAttr->getLocation(), - SKEPAttr->getKernelName()); - } + if (!SKEPAttr->getKernelName()->isDependentType() && + CheckSYCLKernelName(SemaRef, SKEPAttr->getLocation(), + SKEPAttr->getKernelName())) + SKEPAttr->setInvalidAttr(); // Ensure that an attribute present on the previous declaration // matches the one on this declaration. FunctionDecl *PrevFD = FD->getPreviousDecl(); if (PrevFD && !PrevFD->isInvalidDecl()) { const auto *PrevSKEPAttr = PrevFD->getAttr<SYCLKernelEntryPointAttr>(); - if (PrevSKEPAttr) { + if (PrevSKEPAttr && !PrevSKEPAttr->isInvalidAttr()) { if (!getASTContext().hasSameType(SKEPAttr->getKernelName(), PrevSKEPAttr->getKernelName())) { Diag(SKEPAttr->getLocation(), diag::err_sycl_entry_point_invalid_redeclaration) << SKEPAttr->getKernelName() << PrevSKEPAttr->getKernelName(); Diag(PrevSKEPAttr->getLocation(), diag::note_previous_decl) << PrevFD; + SKEPAttr->setInvalidAttr(); } } } @@ -291,29 +293,36 @@ void SemaSYCL::CheckSYCLEntryPointFunctionDecl(FunctionDecl *FD) { if (!MD->isStatic()) { Diag(SKEPAttr->getLocation(), diag::err_sycl_entry_point_invalid) << /*non-static member function*/ 0; + SKEPAttr->setInvalidAttr(); } } if (FD->isVariadic()) { Diag(SKEPAttr->getLocation(), diag::err_sycl_entry_point_invalid) << /*variadic function*/ 1; + SKEPAttr->setInvalidAttr(); } if (FD->isConsteval()) { Diag(SKEPAttr->getLocation(), diag::err_sycl_entry_point_invalid) << /*consteval function*/ 5; + SKEPAttr->setInvalidAttr(); } else if (FD->isConstexpr()) { Diag(SKEPAttr->getLocation(), diag::err_sycl_entry_point_invalid) << /*constexpr function*/ 4; + SKEPAttr->setInvalidAttr(); } if (FD->isNoReturn()) { Diag(SKEPAttr->getLocation(), diag::err_sycl_entry_point_invalid) << /*noreturn function*/ 6; + SKEPAttr->setInvalidAttr(); } if (!FD->getReturnType()->isVoidType()) { Diag(SKEPAttr->getLocation(), diag::err_sycl_entry_point_return_type); + SKEPAttr->setInvalidAttr(); } - if (!FD->isInvalidDecl() && !FD->isTemplated()) { + if (!FD->isInvalidDecl() && !FD->isTemplated() && + !SKEPAttr->isInvalidAttr()) { const SYCLKernelInfo *SKI = getASTContext().findSYCLKernelInfo(SKEPAttr->getKernelName()); if (SKI) { @@ -323,6 +332,7 @@ void SemaSYCL::CheckSYCLEntryPointFunctionDecl(FunctionDecl *FD) { Diag(FD->getLocation(), diag::err_sycl_kernel_name_conflict); Diag(SKI->getKernelEntryPointDecl()->getLocation(), diag::note_previous_declaration); + SKEPAttr->setInvalidAttr(); } } else { getASTContext().registerSYCLEntryPointFunction(FD); diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp index e65983f2013730..13e00c6e591251 100644 --- a/clang/lib/Serialization/ASTReaderDecl.cpp +++ b/clang/lib/Serialization/ASTReaderDecl.cpp @@ -1134,7 +1134,7 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) { // the presence of a sycl_kernel_entry_point attribute, register it so that // associated metadata is recreated. if (FD->hasAttr<SYCLKernelEntryPointAttr>()) { - const auto *SKEPAttr = FD->getAttr<SYCLKernelEntryPointAttr>(); + auto *SKEPAttr = FD->getAttr<SYCLKernelEntryPointAttr>(); ASTContext &C = Reader.getContext(); const SYCLKernelInfo *SKI = C.findSYCLKernelInfo(SKEPAttr->getKernelName()); if (SKI) { @@ -1142,6 +1142,7 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) { Reader.Diag(FD->getLocation(), diag::err_sycl_kernel_name_conflict); Reader.Diag(SKI->getKernelEntryPointDecl()->getLocation(), diag::note_previous_declaration); + SKEPAttr->setInvalidAttr(); } } else { C.registerSYCLEntryPointFunction(FD); diff --git a/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-kernel-name.cpp b/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-kernel-name.cpp index 989aa5ba06f893..3b12da0fc3ef26 100644 --- a/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-kernel-name.cpp +++ b/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-kernel-name.cpp @@ -85,3 +85,18 @@ struct B15; // expected-note@+1 {{previous declaration is here}} [[clang::sycl_kernel_entry_point(B15)]] void bad15_1(); [[clang::sycl_kernel_entry_point(B15)]] void bad15_2(); + +struct B16_1; +struct B16_2; +// expected-error@+4 {{'sycl_kernel_entry_point' kernel name argument does not match prior declaration: 'B16_2' vs 'B16_1'}} +// expected-note@+1 {{'bad16' declared here}} +[[clang::sycl_kernel_entry_point(B16_1)]] void bad16(); +void bad16(); // The attribute from the previous declaration is inherited. +[[clang::sycl_kernel_entry_point(B16_2)]] void bad16(); + +template<int> +struct B17 { + // expected-error@+1 {{'int' is not a valid SYCL kernel name type; a class type is required}} + [[clang::sycl_kernel_entry_point(int)]] + static void bad_17(); +}; >From 5eeff88828cd506abbcfa796da2f70ed25423080 Mon Sep 17 00:00:00 2001 From: Tom Honermann <tom.honerm...@intel.com> Date: Mon, 23 Dec 2024 14:27:31 -0800 Subject: [PATCH 4/8] Fixes to address the first round of code review comments from Erich. --- .../clang/Basic/DiagnosticSemaKinds.td | 7 ++++--- clang/lib/Sema/SemaSYCL.cpp | 19 ++++++++++++------- ...-kernel-entry-point-attr-appertainment.cpp | 4 ++-- ...cl-kernel-entry-point-attr-kernel-name.cpp | 18 +++++++++--------- .../sycl-kernel-entry-point-attr-sfinae.cpp | 2 +- 5 files changed, 28 insertions(+), 22 deletions(-) diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 2495fbc4ce0765..cb6f8a26b83bb9 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -12411,8 +12411,9 @@ def err_sycl_special_type_num_init_method : Error< // SYCL kernel entry point diagnostics def err_sycl_entry_point_invalid : Error< "'sycl_kernel_entry_point' attribute cannot be applied to a" - " %select{non-static member|variadic|deleted|defaulted|constexpr|consteval|" - "noreturn|coroutine}0 function">; + " %select{non-static member function|variadic function|deleted function|" + "defaulted function|constexpr function|consteval function|" + "function declared with the 'noreturn' attribute|coroutine}0">; def err_sycl_entry_point_invalid_redeclaration : Error< "'sycl_kernel_entry_point' kernel name argument does not match prior" " declaration%diff{: $ vs $|}0,1">; @@ -12420,7 +12421,7 @@ def err_sycl_kernel_name_conflict : Error< "'sycl_kernel_entry_point' kernel name argument conflicts with a previous" " declaration">; def warn_sycl_kernel_name_not_a_class_type : Warning< - "%0 is not a valid SYCL kernel name type; a class type is required">, + "%0 is not a valid SYCL kernel name type; a non-union class type is required">, InGroup<DiagGroup<"nonportable-sycl">>, DefaultError; def warn_sycl_entry_point_redundant_declaration : Warning< "redundant 'sycl_kernel_entry_point' attribute">, InGroup<RedundantAttribute>; diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp index 0ed9246b2319a3..f7afadfd1a37b5 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -209,7 +209,13 @@ void SemaSYCL::handleKernelEntryPointAttr(Decl *D, const ParsedAttr &AL) { SYCLKernelEntryPointAttr(SemaRef.Context, AL, TSI)); } -static SourceLocation SourceLocationForType(QualType QT) { +// Given a potentially qualified type, SourceLocationForUserDeclaredType() +// returns the source location of the canonical declaration of the unqualified +// desugared user declared type, if any. For non-user declared types, an +// invalid source location is returned. The intended usage of this function +// is to identify an appropriate source location, if any, for a +// "entity declared here" diagnostic note. +static SourceLocation SourceLocationForUserDeclaredType(QualType QT) { SourceLocation Loc; const Type *T = QT->getUnqualifiedDesugaredType(); if (const TagType *TT = dyn_cast<TagType>(T)) @@ -233,7 +239,7 @@ static bool CheckSYCLKernelName(Sema &S, SourceLocation Loc, // clarification from the SYCL WG. // https://github.com/KhronosGroup/SYCL-Docs/issues/568 S.Diag(Loc, diag::warn_sycl_kernel_name_not_a_class_type) << KernelName; - SourceLocation DeclTypeLoc = SourceLocationForType(KernelName); + SourceLocation DeclTypeLoc = SourceLocationForUserDeclaredType(KernelName); if (DeclTypeLoc.isValid()) S.Diag(DeclTypeLoc, diag::note_entity_declared_at) << KernelName; return true; @@ -246,10 +252,9 @@ void SemaSYCL::CheckSYCLEntryPointFunctionDecl(FunctionDecl *FD) { // Ensure that all attributes present on the declaration are consistent // and warn about any redundant ones. SYCLKernelEntryPointAttr *SKEPAttr = nullptr; - for (auto SAI = FD->specific_attr_begin<SYCLKernelEntryPointAttr>(); - SAI != FD->specific_attr_end<SYCLKernelEntryPointAttr>(); ++SAI) { + for (auto* SAI : FD->specific_attrs<SYCLKernelEntryPointAttr>()) { if (!SKEPAttr) { - SKEPAttr = *SAI; + SKEPAttr = SAI; continue; } if (!getASTContext().hasSameType(SAI->getKernelName(), @@ -289,7 +294,7 @@ void SemaSYCL::CheckSYCLEntryPointFunctionDecl(FunctionDecl *FD) { } } - if (auto *MD = dyn_cast<CXXMethodDecl>(FD)) { + if (const auto *MD = dyn_cast<CXXMethodDecl>(FD)) { if (!MD->isStatic()) { Diag(SKEPAttr->getLocation(), diag::err_sycl_entry_point_invalid) << /*non-static member function*/ 0; @@ -312,7 +317,7 @@ void SemaSYCL::CheckSYCLEntryPointFunctionDecl(FunctionDecl *FD) { } if (FD->isNoReturn()) { Diag(SKEPAttr->getLocation(), diag::err_sycl_entry_point_invalid) - << /*noreturn function*/ 6; + << /*function declared with the 'noreturn' attribute*/ 6; SKEPAttr->setInvalidAttr(); } diff --git a/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-appertainment.cpp b/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-appertainment.cpp index 5f638061a96408..a700c06dafaccc 100644 --- a/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-appertainment.cpp +++ b/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-appertainment.cpp @@ -208,7 +208,7 @@ template<void (fp [[clang::sycl_kernel_entry_point(BADKN<18>)]])()> void bad18(); #if __cplusplus >= 202002L -// expected-error@+1 {{'sycl_kernel_entry_point' attribute cannot be applied to a coroutine function}} +// expected-error@+1 {{'sycl_kernel_entry_point' attribute cannot be applied to a coroutine}} [[clang::sycl_kernel_entry_point(BADKN<19>)]] void bad19() { co_return; @@ -245,7 +245,7 @@ constexpr void bad24() {} consteval void bad25() {} #endif -// expected-error@+1 {{'sycl_kernel_entry_point' attribute cannot be applied to a noreturn function}} +// expected-error@+1 {{'sycl_kernel_entry_point' attribute cannot be applied to a function declared with the 'noreturn' attribute}} [[clang::sycl_kernel_entry_point(BADKN<26>)]] [[noreturn]] void bad26(); diff --git a/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-kernel-name.cpp b/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-kernel-name.cpp index 3b12da0fc3ef26..61b0d8d3fd674c 100644 --- a/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-kernel-name.cpp +++ b/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-kernel-name.cpp @@ -13,33 +13,33 @@ struct S1; clang::sycl_kernel_entry_point(S1)]] void ok1(); -// expected-error@+1 {{'int' is not a valid SYCL kernel name type; a class type is required}} +// expected-error@+1 {{'int' is not a valid SYCL kernel name type; a non-union class type is required}} [[clang::sycl_kernel_entry_point(int)]] void bad2(); -// expected-error@+1 {{'int ()' is not a valid SYCL kernel name type; a class type is required}} +// expected-error@+1 {{'int ()' is not a valid SYCL kernel name type; a non-union class type is required}} [[clang::sycl_kernel_entry_point(int())]] void bad3(); -// expected-error@+1 {{'int (*)()' is not a valid SYCL kernel name type; a class type is required}} +// expected-error@+1 {{'int (*)()' is not a valid SYCL kernel name type; a non-union class type is required}} [[clang::sycl_kernel_entry_point(int(*)())]] void bad4(); -// expected-error@+1 {{'int (&)()' is not a valid SYCL kernel name type; a class type is required}} +// expected-error@+1 {{'int (&)()' is not a valid SYCL kernel name type; a non-union class type is required}} [[clang::sycl_kernel_entry_point(int(&)())]] void bad5(); -// expected-error@+1 {{'decltype(nullptr)' (aka 'std::nullptr_t') is not a valid SYCL kernel name type; a class type is required}} +// expected-error@+1 {{'decltype(nullptr)' (aka 'std::nullptr_t') is not a valid SYCL kernel name type; a non-union class type is required}} [[clang::sycl_kernel_entry_point(decltype(nullptr))]] void bad6(); union U7; // #U7-decl -// expected-error@+2 {{'U7' is not a valid SYCL kernel name type; a class type is required}} +// expected-error@+2 {{'U7' is not a valid SYCL kernel name type; a non-union class type is required}} // expected-note@#U7-decl {{'U7' declared here}} [[clang::sycl_kernel_entry_point(U7)]] void bad7(); enum E8 {}; // #E8-decl -// expected-error@+2 {{'E8' is not a valid SYCL kernel name type; a class type is required}} +// expected-error@+2 {{'E8' is not a valid SYCL kernel name type; a non-union class type is required}} // expected-note@#E8-decl {{'E8' declared here}} [[clang::sycl_kernel_entry_point(E8)]] void bad8(); enum E9 : int; // #E9-decl -// expected-error@+2 {{'E9' is not a valid SYCL kernel name type; a class type is required}} +// expected-error@+2 {{'E9' is not a valid SYCL kernel name type; a non-union class type is required}} // expected-note@#E9-decl {{'E9' declared here}} [[clang::sycl_kernel_entry_point(E9)]] void bad9(); @@ -96,7 +96,7 @@ void bad16(); // The attribute from the previous declaration is inherited. template<int> struct B17 { - // expected-error@+1 {{'int' is not a valid SYCL kernel name type; a class type is required}} + // expected-error@+1 {{'int' is not a valid SYCL kernel name type; a non-union class type is required}} [[clang::sycl_kernel_entry_point(int)]] static void bad_17(); }; diff --git a/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-sfinae.cpp b/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-sfinae.cpp index 872ecbd4844aad..4c615704196299 100644 --- a/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-sfinae.cpp +++ b/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-sfinae.cpp @@ -51,7 +51,7 @@ struct Select3 { using bad_type = int; using good_type = S3; }; -// expected-error@+5 {{'typename Select3::bad_type' (aka 'int') is not a valid SYCL kernel name type; a class type is required}} +// expected-error@+5 {{'typename Select3::bad_type' (aka 'int') is not a valid SYCL kernel name type; a non-union class type is required}} // expected-note@+9 {{in instantiation of function template specialization 'ok3<Select3>' requested here}} template<typename T> [[clang::sycl_kernel_entry_point(typename T::good_type)]] void ok3(int) {} >From 97f58f486c770b2a562609ea9b3c7d902c8c761c Mon Sep 17 00:00:00 2001 From: Tom Honermann <tom.honerm...@intel.com> Date: Mon, 23 Dec 2024 20:38:33 -0800 Subject: [PATCH 5/8] Squash; Fix clang-format complaints. Again. --- clang/lib/Sema/SemaSYCL.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp index f7afadfd1a37b5..b8cc137f31b7ef 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -252,7 +252,7 @@ void SemaSYCL::CheckSYCLEntryPointFunctionDecl(FunctionDecl *FD) { // Ensure that all attributes present on the declaration are consistent // and warn about any redundant ones. SYCLKernelEntryPointAttr *SKEPAttr = nullptr; - for (auto* SAI : FD->specific_attrs<SYCLKernelEntryPointAttr>()) { + for (auto *SAI : FD->specific_attrs<SYCLKernelEntryPointAttr>()) { if (!SKEPAttr) { SKEPAttr = SAI; continue; >From da651f6a078de71ef43828232455fb4d379ff7df Mon Sep 17 00:00:00 2001 From: Tom Honermann <tom.honerm...@intel.com> Date: Mon, 23 Dec 2024 21:28:48 -0800 Subject: [PATCH 6/8] Added tests for dependent and non-dependent hidden friend functions. --- ...-kernel-entry-point-attr-appertainment.cpp | 31 +++++++++++++------ ...cl-kernel-entry-point-attr-kernel-name.cpp | 18 ++++++++++- 2 files changed, 38 insertions(+), 11 deletions(-) diff --git a/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-appertainment.cpp b/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-appertainment.cpp index a700c06dafaccc..599c29f06d6bc7 100644 --- a/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-appertainment.cpp +++ b/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-appertainment.cpp @@ -78,7 +78,7 @@ struct S6 { static void ok6(); }; -// Dependent friend function. +// Dependent hidden friend definition. template<typename KNT> struct S7 { [[clang::sycl_kernel_entry_point(KNT)]] @@ -88,24 +88,35 @@ void test_ok7() { ok7(S7<KN<7>>{}); } +// Non-dependent hidden friend definition. +struct S8Base {}; +template<typename> +struct S8 : S8Base { + [[clang::sycl_kernel_entry_point(KN<8>)]] + friend void ok8(const S8Base&) {} +}; +void test_ok8() { + ok8(S8<int>{}); +} + // The sycl_kernel_entry_point attribute must match across declarations and // cannot be added for the first time after a definition. -[[clang::sycl_kernel_entry_point(KN<8>)]] -void ok8(); -[[clang::sycl_kernel_entry_point(KN<8>)]] -void ok8(); [[clang::sycl_kernel_entry_point(KN<9>)]] void ok9(); -void ok9() {} -void ok10(); +[[clang::sycl_kernel_entry_point(KN<9>)]] +void ok9(); [[clang::sycl_kernel_entry_point(KN<10>)]] +void ok10(); void ok10() {} +void ok11(); +[[clang::sycl_kernel_entry_point(KN<11>)]] +void ok11() {} using VOID = void; -[[clang::sycl_kernel_entry_point(KN<11>)]] -VOID ok11(); [[clang::sycl_kernel_entry_point(KN<12>)]] -const void ok12(); +VOID ok12(); +[[clang::sycl_kernel_entry_point(KN<13>)]] +const void ok13(); //////////////////////////////////////////////////////////////////////////////// diff --git a/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-kernel-name.cpp b/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-kernel-name.cpp index 61b0d8d3fd674c..78dd89696c02d4 100644 --- a/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-kernel-name.cpp +++ b/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-kernel-name.cpp @@ -98,5 +98,21 @@ template<int> struct B17 { // expected-error@+1 {{'int' is not a valid SYCL kernel name type; a non-union class type is required}} [[clang::sycl_kernel_entry_point(int)]] - static void bad_17(); + static void bad17(); }; + +template<int> +struct B18 { + // expected-error@+1 {{'int' is not a valid SYCL kernel name type; a non-union class type is required}} + [[clang::sycl_kernel_entry_point(int)]] + friend void bad18() {} +}; + +template<typename KNT> +struct B19 { + // expected-error@+1 {{'int' is not a valid SYCL kernel name type; a non-union class type is required}} + [[clang::sycl_kernel_entry_point(KNT)]] + friend void bad19() {} +}; +// expected-note@+1 {{in instantiation of template class 'B19<int>' requested here}} +B19<int> b19; >From c0044ab0458789c1e43b7286aaceb2c9caba261e Mon Sep 17 00:00:00 2001 From: Tom Honermann <tom.honerm...@intel.com> Date: Tue, 24 Dec 2024 15:20:12 -0800 Subject: [PATCH 7/8] Fixes to address issues with diagnostics for templated functions, lambdas, and dependent return types. This change addresses issues with diagnostics generation for various uses of the sycl_kernel_entry_point attribute: - Missing diagnostics for deleted or defaulted functions declared in a dependent context. - Missing diagnostics for lambda expressions. - Spurious diagnostics for functions with a dependent return type; a diagnostic was previously issued complaining of a non-void type. - Missing diagnostics for functions with a deduced return type. --- .../clang/Basic/DiagnosticSemaKinds.td | 3 + clang/lib/Sema/SemaDecl.cpp | 13 ++- clang/lib/Sema/SemaLambda.cpp | 5 ++ clang/lib/Sema/SemaSYCL.cpp | 20 ++++- ...-kernel-entry-point-attr-appertainment.cpp | 82 +++++++++++++++++++ 5 files changed, 115 insertions(+), 8 deletions(-) diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index cb6f8a26b83bb9..9299def004cb71 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -12431,6 +12431,9 @@ def err_sycl_entry_point_after_definition : Error< def err_sycl_entry_point_return_type : Error< "'sycl_kernel_entry_point' attribute only applies to functions with a" " 'void' return type">; +def err_sycl_entry_point_deduced_return_type : Error< + "'sycl_kernel_entry_point' attribute only applies to functions with a" + " non-deduced 'void' return type">; def warn_cuda_maxclusterrank_sm_90 : Warning< "maxclusterrank requires sm_90 or higher, CUDA arch provided: %0, ignoring " diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index a94eaa6788cfc6..7ed39f95f3ab73 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -12156,7 +12156,7 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, if (LangOpts.OpenMP) OpenMP().ActOnFinishedFunctionDefinitionInOpenMPAssumeScope(NewFD); - if (LangOpts.isSYCL() && NewFD->hasAttr<SYCLKernelEntryPointAttr>()) + if (NewFD->hasAttr<SYCLKernelEntryPointAttr>()) SYCL().CheckSYCLEntryPointFunctionDecl(NewFD); // Semantic checking for this function declaration (in isolation). @@ -15990,17 +15990,16 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, } // Diagnose invalid SYCL kernel entry point function declarations. - if (FD && !FD->isInvalidDecl() && !FD->isTemplated() && - FD->hasAttr<SYCLKernelEntryPointAttr>()) { + if (FD && !FD->isInvalidDecl() && FD->hasAttr<SYCLKernelEntryPointAttr>()) { SYCLKernelEntryPointAttr *SKEPAttr = FD->getAttr<SYCLKernelEntryPointAttr>(); - if (FD->isDeleted()) { + if (FD->isDefaulted()) { Diag(SKEPAttr->getLocation(), diag::err_sycl_entry_point_invalid) - << /*deleted function*/ 2; + << /*defaulted function*/ 3; SKEPAttr->setInvalidAttr(); - } else if (FD->isDefaulted()) { + } else if (FD->isDeleted()) { Diag(SKEPAttr->getLocation(), diag::err_sycl_entry_point_invalid) - << /*defaulted function*/ 3; + << /*deleted function*/ 2; SKEPAttr->setInvalidAttr(); } else if (FSI->isCoroutine()) { Diag(SKEPAttr->getLocation(), diag::err_sycl_entry_point_invalid) diff --git a/clang/lib/Sema/SemaLambda.cpp b/clang/lib/Sema/SemaLambda.cpp index a67c0b2b367d1a..f2c3a816b3b5d3 100644 --- a/clang/lib/Sema/SemaLambda.cpp +++ b/clang/lib/Sema/SemaLambda.cpp @@ -24,6 +24,7 @@ #include "clang/Sema/SemaCUDA.h" #include "clang/Sema/SemaInternal.h" #include "clang/Sema/SemaOpenMP.h" +#include "clang/Sema/SemaSYCL.h" #include "clang/Sema/Template.h" #include "llvm/ADT/STLExtras.h" #include <optional> @@ -1948,6 +1949,10 @@ ExprResult Sema::BuildCaptureInit(const Capture &Cap, ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body) { LambdaScopeInfo LSI = *cast<LambdaScopeInfo>(FunctionScopes.back()); + + if (LSI.CallOperator->hasAttr<SYCLKernelEntryPointAttr>()) + SYCL().CheckSYCLEntryPointFunctionDecl(LSI.CallOperator); + ActOnFinishFunctionBody(LSI.CallOperator, Body); return BuildLambdaExpr(StartLoc, Body->getEndLoc(), &LSI); diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp index b8cc137f31b7ef..fbd68a09b47db9 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -301,11 +301,23 @@ void SemaSYCL::CheckSYCLEntryPointFunctionDecl(FunctionDecl *FD) { SKEPAttr->setInvalidAttr(); } } + if (FD->isVariadic()) { Diag(SKEPAttr->getLocation(), diag::err_sycl_entry_point_invalid) << /*variadic function*/ 1; SKEPAttr->setInvalidAttr(); } + + if (FD->isDefaulted()) { + Diag(SKEPAttr->getLocation(), diag::err_sycl_entry_point_invalid) + << /*defaulted function*/ 3; + SKEPAttr->setInvalidAttr(); + } else if (FD->isDeleted()) { + Diag(SKEPAttr->getLocation(), diag::err_sycl_entry_point_invalid) + << /*deleted function*/ 2; + SKEPAttr->setInvalidAttr(); + } + if (FD->isConsteval()) { Diag(SKEPAttr->getLocation(), diag::err_sycl_entry_point_invalid) << /*consteval function*/ 5; @@ -315,13 +327,19 @@ void SemaSYCL::CheckSYCLEntryPointFunctionDecl(FunctionDecl *FD) { << /*constexpr function*/ 4; SKEPAttr->setInvalidAttr(); } + if (FD->isNoReturn()) { Diag(SKEPAttr->getLocation(), diag::err_sycl_entry_point_invalid) << /*function declared with the 'noreturn' attribute*/ 6; SKEPAttr->setInvalidAttr(); } - if (!FD->getReturnType()->isVoidType()) { + if (FD->getReturnType()->isUndeducedType()) { + Diag(SKEPAttr->getLocation(), + diag::err_sycl_entry_point_deduced_return_type); + SKEPAttr->setInvalidAttr(); + } else if (!FD->getReturnType()->isDependentType() && + !FD->getReturnType()->isVoidType()) { Diag(SKEPAttr->getLocation(), diag::err_sycl_entry_point_return_type); SKEPAttr->setInvalidAttr(); } diff --git a/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-appertainment.cpp b/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-appertainment.cpp index 599c29f06d6bc7..847ea7ea1bb07f 100644 --- a/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-appertainment.cpp +++ b/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-appertainment.cpp @@ -1,5 +1,6 @@ // RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++17 -fsyntax-only -fsycl-is-device -verify %s // RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++20 -fsyntax-only -fsycl-is-device -verify %s +// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++23 -fsyntax-only -fsycl-is-device -verify %s // These tests validate appertainment for the sycl_kernel_entry_point attribute. @@ -118,6 +119,17 @@ VOID ok12(); [[clang::sycl_kernel_entry_point(KN<13>)]] const void ok13(); +#if __cplusplus >= 202302L +auto ok14 = [] [[clang::sycl_kernel_entry_point(KN<14>)]] static -> void {}; +#endif + +template<typename KNT, typename T> +struct S15 { + // Don't diagnose a dependent return type as a non-void type. + [[clang::sycl_kernel_entry_point(KNT)]] + static T ok15(); +}; + //////////////////////////////////////////////////////////////////////////////// // Invalid declarations. @@ -264,3 +276,73 @@ consteval void bad25() {} __attribute__((target("avx"))) void bad27(); [[clang::sycl_kernel_entry_point(BADKN<27>)]] __attribute__((target("sse4.2"))) void bad27(); + +template<typename KNT> +struct B28 { + // expected-error@+1 {{'sycl_kernel_entry_point' attribute cannot be applied to a deleted function}} + [[clang::sycl_kernel_entry_point(KNT)]] + friend void bad28() = delete; +}; + +#if __cplusplus >= 202002L +template<typename KNT, typename T> +struct B29 { + // expected-error@+1 {{'sycl_kernel_entry_point' attribute cannot be applied to a defaulted function}} + [[clang::sycl_kernel_entry_point(KNT)]] + friend T operator==(B29, B29) = default; +}; +#endif + +#if __cplusplus >= 202002L +template<typename KNT> +struct B30 { + // expected-error@+1 {{'sycl_kernel_entry_point' attribute cannot be applied to a coroutine}} + [[clang::sycl_kernel_entry_point(KNT)]] + friend void bad30() { co_return; } +}; +#endif + +template<typename KNT> +struct B31 { + // expected-error@+1 {{'sycl_kernel_entry_point' attribute cannot be applied to a variadic function}} + [[clang::sycl_kernel_entry_point(KNT)]] + friend void bad31(...) {} +}; + +template<typename KNT> +struct B32 { + // expected-error@+1 {{'sycl_kernel_entry_point' attribute cannot be applied to a constexpr function}} + [[clang::sycl_kernel_entry_point(KNT)]] + friend constexpr void bad32() {} +}; + +#if __cplusplus >= 202002L +template<typename KNT> +struct B33 { + // expected-error@+1 {{'sycl_kernel_entry_point' attribute cannot be applied to a consteval function}} + [[clang::sycl_kernel_entry_point(KNT)]] + friend consteval void bad33() {} +}; +#endif + +template<typename KNT> +struct B34 { + // expected-error@+1 {{'sycl_kernel_entry_point' attribute cannot be applied to a function declared with the 'noreturn' attribute}} + [[clang::sycl_kernel_entry_point(KNT)]] + [[noreturn]] friend void bad34() {} +}; + +#if __cplusplus >= 202302L +// expected-error@+1 {{'sycl_kernel_entry_point' attribute cannot be applied to a non-static member function}} +auto bad35 = [] [[clang::sycl_kernel_entry_point(BADKN<35>)]] -> void {}; +#endif + +#if __cplusplus >= 202302L +// expected-error@+1 {{'sycl_kernel_entry_point' attribute only applies to functions with a non-deduced 'void' return type}} +auto bad36 = [] [[clang::sycl_kernel_entry_point(BADKN<36>)]] static {}; +#endif + +#if __cplusplus >= 202302L +// expected-error@+1 {{'sycl_kernel_entry_point' attribute cannot be applied to a coroutine}} +auto bad37 = [] [[clang::sycl_kernel_entry_point(BADKN<37>)]] static -> void { co_return; }; +#endif >From 1a0898f72cb3d9dcec496f2dc57b3cd78aebbe2a Mon Sep 17 00:00:00 2001 From: Tom Honermann <tom.honerm...@intel.com> Date: Tue, 24 Dec 2024 17:36:12 -0800 Subject: [PATCH 8/8] Squash; Fix clang-format complaints. Again. --- clang/lib/Sema/SemaSYCL.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp index fbd68a09b47db9..ce53990fdcb18f 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -339,7 +339,7 @@ void SemaSYCL::CheckSYCLEntryPointFunctionDecl(FunctionDecl *FD) { diag::err_sycl_entry_point_deduced_return_type); SKEPAttr->setInvalidAttr(); } else if (!FD->getReturnType()->isDependentType() && - !FD->getReturnType()->isVoidType()) { + !FD->getReturnType()->isVoidType()) { Diag(SKEPAttr->getLocation(), diag::err_sycl_entry_point_return_type); SKEPAttr->setInvalidAttr(); } _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits