================ @@ -206,3 +208,124 @@ 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()) { ---------------- erichkeane wrote:
Again, `isTemplated` doesn't mean the function is a template. So this would cause problems with things like friend functions in a template context. https://github.com/llvm/llvm-project/pull/120327 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits