diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 11bf8b7f921e9..5092a4980ccf2 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -10815,7 +10815,7 @@ def err_sycl_non_trivially_copy_ctor_dtor_type def err_sycl_non_std_layout_type : Error< "kernel parameter has non-standard layout class/struct type %0">; def err_conflicting_sycl_kernel_attributes : Error< - "conflicting attributes applied to a SYCL kernel">; + "conflicting attributes applied to a SYCL kernel or SYCL_EXTERNAL function">; def err_conflicting_sycl_function_attributes : Error< "%0 attribute conflicts with '%1' attribute">; def err_sycl_x_y_z_arguments_must_be_one : Error< diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 1abab50c2dc66..6dbce1c450b58 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -12556,7 +12556,7 @@ class Sema final { private: // We store SYCL Kernels here and handle separately -- which is a hack. // FIXME: It would be best to refactor this. - SmallVector SyclDeviceDecls; + llvm::SetVector SyclDeviceDecls; // SYCL integration header instance for current compilation unit this Sema // is associated with. std::unique_ptr SyclIntHeader; @@ -12567,8 +12567,8 @@ class Sema final { bool ConstructingOpenCLKernel = false; public: - void addSyclDeviceDecl(Decl *d) { SyclDeviceDecls.push_back(d); } - SmallVectorImpl &syclDeviceDecls() { return SyclDeviceDecls; } + void addSyclDeviceDecl(Decl *d) { SyclDeviceDecls.insert(d); } + llvm::SetVector &syclDeviceDecls() { return SyclDeviceDecls; } /// Lazily creates and returns SYCL integration header instance. SYCLIntegrationHeader &getSyclIntegrationHeader() { diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp index e8c8c614a61a9..a17ea28195a45 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -1460,6 +1460,15 @@ void Sema::MarkDevice(void) { // it is recursive. MarkDeviceFunction Marker(*this); Marker.SYCLCG.addToCallGraph(getASTContext().getTranslationUnitDecl()); + + // Iterate through SYCL_EXTERNAL functions and add them to the device decls. + for (const auto &entry : *Marker.SYCLCG.getRoot()) { + if (auto *FD = dyn_cast(entry.Callee->getDecl())) { + if (FD->hasAttr() && !FD->hasAttr()) + addSyclDeviceDecl(FD); + } + } + for (Decl *D : syclDeviceDecls()) { if (auto SYCLKernel = dyn_cast(D)) { llvm::SmallPtrSet VisitedSet; diff --git a/clang/test/SemaSYCL/reqd-sub-group-size-device.cpp b/clang/test/SemaSYCL/reqd-sub-group-size-device.cpp index 1e8298f27d5b3..8345f1f2cdacc 100644 --- a/clang/test/SemaSYCL/reqd-sub-group-size-device.cpp +++ b/clang/test/SemaSYCL/reqd-sub-group-size-device.cpp @@ -48,6 +48,17 @@ void bar() { kernel([]() [[cl::intel_reqd_sub_group_size(2)]] { }); } +#ifdef TRIGGER_ERROR +// expected-note@+1 {{conflicting attribute is here}} +[[cl::intel_reqd_sub_group_size(2)]] void sg_size2() {} + +// expected-note@+2 {{conflicting attribute is here}} +// expected-error@+1 {{conflicting attributes applied to a SYCL kernel}} +[[cl::intel_reqd_sub_group_size(4)]] __attribute__((sycl_device)) void sg_size4() { + sg_size2(); +} +#endif + // CHECK: FunctionDecl {{.*}} {{.*}}kernel_name1 // CHECK: IntelReqdSubGroupSizeAttr {{.*}} 16 // CHECK: FunctionDecl {{.*}} {{.*}}kernel_name2