[clang] [clang][SYCL] Add additional Sema rules for SYCL kernel parameters (PR #208571)
Ian Li via cfe-commits
cfe-commits at lists.llvm.org
Fri Jul 17 09:13:58 PDT 2026
https://github.com/ianayl updated https://github.com/llvm/llvm-project/pull/208571
>From bb73b24cf5e0a77209576f8d8253f2793d848050 Mon Sep 17 00:00:00 2001
From: "Li, Ian" <ian.li at intel.com>
Date: Tue, 7 Jul 2026 07:26:01 -0700
Subject: [PATCH 01/11] Initial work
---
.../clang/Basic/DiagnosticSemaKinds.td | 4 +
clang/lib/Sema/SemaSYCL.cpp | 30 +++++
.../sycl-kernel-param-restrictions.cpp | 107 ++++++++++++++++++
3 files changed, 141 insertions(+)
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 86b765fdf1fab..3f393fa574434 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -13514,6 +13514,10 @@ def err_sycl_special_type_num_init_method : Error<
"method defined">;
def err_sycl_device_invalid_target : Error<
"%0 is not a supported SYCL device target">;
+def warn_sycl_kernel_has_ptr_param : Warning<
+ "pointers parameters in SYCL kernels must point to device-accessible memory, "
+ "i.e. the USM">,
+ InGroup<NonPortableSYCL>, DefaultIgnore;
// SYCL external attribute diagnostics
def err_sycl_external_invalid_linkage : Error<
diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp
index b942f19761f40..0b35172c3deb4 100644
--- a/clang/lib/Sema/SemaSYCL.cpp
+++ b/clang/lib/Sema/SemaSYCL.cpp
@@ -750,6 +750,36 @@ class KernelParamsChecker : public ConstSubobjectVisitor<KernelParamsChecker> {
// invalid use of a reference.
IsValid = false;
return false;
+ }
+
+ Ty.dump();
+ if (Ty->isAtomicType() ||
+ Ty->isStructureTypeWithFlexibleArrayMember() ||
+ Ty->isVariablyModifiedType()) {
+
+ auto DirectParent = ObjectAccessPath.back();
+ auto *DirectFieldParent = cast<const FieldDecl *>(DirectParent);
+ SemaSYCLRef.Diag(DirectFieldParent->getLocation(),
+ diag::err_bad_kernel_param_type)
+ << DirectFieldParent->getType();
+ emitObjectAccessPathNotes();
+
+ IsValid = false;
+ return false;
+ } /*
+ } else if (0 ) { // TODO detect virtual base class
+
+ } // TODO introduce warning to detect pointers
+ // "sycl portability warning: it is user's responsibility to ensure pointers being used are USM"
+ */
+ // Warn about pointer parameters in SYCL kernels if non-portable SYCL
+ // warnings are enabled.
+ if (Ty->isPointerType()) {
+ auto DirectParent = ObjectAccessPath.back();
+ auto *DirectFieldParent = cast<const FieldDecl *>(DirectParent);
+ SemaSYCLRef.Diag(DirectFieldParent->getLocation(),
+ diag::warn_sycl_kernel_has_ptr_param);
+ emitObjectAccessPathNotes();
}
return true;
}
diff --git a/clang/test/SemaSYCL/sycl-kernel-param-restrictions.cpp b/clang/test/SemaSYCL/sycl-kernel-param-restrictions.cpp
index 66aa00da18a04..f93cc17d72d89 100644
--- a/clang/test/SemaSYCL/sycl-kernel-param-restrictions.cpp
+++ b/clang/test/SemaSYCL/sycl-kernel-param-restrictions.cpp
@@ -1,6 +1,8 @@
// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++17 -fsyntax-only -Wno-vla-cxx-extension -fsycl-is-host -verify %s
// RUN: %clang_cc1 -triple spirv64 -std=c++17 -fsyntax-only -Wno-vla-cxx-extension -fsycl-is-device -verify %s
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++17 -fsyntax-only -Wnonportable-sycl -Wno-vla-cxx-extension -fsycl-is-host -verify=nonportable %s
+
// A unique kernel name type is required for each declared kernel entry point.
template<int, int = 0> struct KN;
@@ -213,3 +215,108 @@ void test() {
}
} // namespace badref7
+
+
+#include <stdatomic.h>
+// Check for atomic parameters and subobjects.
+namespace badref8 {
+// Kernel entry point template definition.
+template<typename KNT, typename T>
+[[clang::sycl_kernel_entry_point(KNT)]]
+void kernel_single_task(T t) {}
+
+struct S {
+ int a;
+ _Atomic int b;
+};
+
+class Kernel {
+ S data{1, 2};
+public:
+ void operator()() { }
+};
+
+void test() {
+ _Atomic int a = 0;
+ // TODO _Atomic(int) a
+ S s{1, 2};
+ S arr[] = {s, s};
+ kernel_single_task<class KN<15>>([=]{ (void)a; });
+ kernel_single_task<class KN<16>>([=]{ (void)s; });
+ kernel_single_task<class KN<17>>([=]{ (void)arr; });
+ kernel_single_task<class KN<18>>(Kernel());
+ // kernel_single_task<class KN<17>>([](S s) { (void)s; }); // DOESNT DETECT
+}
+
+} // namespace badref8
+
+
+// Check for flexible array members -- would not be copyable to device
+namespace badref9 {
+// Kernel entry point template definition.
+template<typename KNT, typename T>
+[[clang::sycl_kernel_entry_point(KNT)]]
+void kernel_single_task(T t) {}
+
+struct FAM {
+ int a;
+ int[] b;
+};
+
+class Kernel {
+ FAM fam;
+public:
+ void operator()() { }
+};
+
+void test() {
+ FAM fam;
+ kernel_single_task<class KN<19>>([=]{ (void)fam; }); // DOESNT DETECT
+ kernel_single_task<class KN<20>>(Kernel());
+}
+
+} // namespace badref9
+
+// Check for variable member array -- would not be copyable to device
+namespace badref10 {
+// Kernel entry point template definition.
+template<typename KNT, typename T>
+[[clang::sycl_kernel_entry_point(KNT)]]
+void kernel_single_task(T t) {}
+
+class Kernel {
+ int len;
+public:
+ Kernel(int l, int vmt[n]) : len(l) {}
+ void operator()(int n, int vmt[n]) { (void)vmt; }
+};
+
+void test() {
+ int n;
+ int Vmt[n];
+ kernel_single_task<class KN<21>>([=](int n, int vmt[n]) { (void)vmt; }); // DOESNT DETECT
+ kernel_single_task<class KN<22>>(Kernel()); // DOESNT DETECT
+ kernel_single_task<class KN<23>>([=]{ (void)Vmt; });
+}
+
+} // namespace badref10
+
+// Check for pointer parameters
+namespace nonportable1 {
+// Kernel entry point template definition.
+template<typename KNT, typename T>
+[[clang::sycl_kernel_entry_point(KNT)]]
+void kernel_single_task(T t) {}
+
+class Kernel {
+public:
+ void operator()(int *ptr) { (void)ptr; }
+};
+
+void test() {
+ int *ptr;
+ kernel_single_task<class KN<24>>(Kernel()); // DOESNT DETECT
+ kernel_single_task<class KN<25>>([=]{ (void)ptr; }); // DOESNT DETECT
+}
+
+} // namespace nonportable1
\ No newline at end of file
>From 57abfe8abd081828564881b6398ac5b079c2f00f Mon Sep 17 00:00:00 2001
From: "Li, Ian" <ian.li at intel.com>
Date: Wed, 8 Jul 2026 08:16:40 -0700
Subject: [PATCH 02/11] Tentative implementation
---
.../clang/Basic/DiagnosticSemaKinds.td | 2 +
clang/lib/Sema/SemaSYCL.cpp | 20 ++++--
.../sycl-kernel-param-restrictions.cpp | 61 ++++++++++---------
3 files changed, 48 insertions(+), 35 deletions(-)
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 3f393fa574434..acef5af0b34f8 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -13518,6 +13518,8 @@ def warn_sycl_kernel_has_ptr_param : Warning<
"pointers parameters in SYCL kernels must point to device-accessible memory, "
"i.e. the USM">,
InGroup<NonPortableSYCL>, DefaultIgnore;
+def err_sycl_kernel_param_has_vbase : Error<
+ "%0 inherits virtual base classes and cannot be used as a SYCL kernel parameter">;
// SYCL external attribute diagnostics
def err_sycl_external_invalid_linkage : Error<
diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp
index 0b35172c3deb4..88b6aefa187f9 100644
--- a/clang/lib/Sema/SemaSYCL.cpp
+++ b/clang/lib/Sema/SemaSYCL.cpp
@@ -766,12 +766,20 @@ class KernelParamsChecker : public ConstSubobjectVisitor<KernelParamsChecker> {
IsValid = false;
return false;
- } /*
- } else if (0 ) { // TODO detect virtual base class
-
- } // TODO introduce warning to detect pointers
- // "sycl portability warning: it is user's responsibility to ensure pointers being used are USM"
- */
+ }
+ if (CXXRecordDecl *RD = Ty->getAsCXXRecordDecl()) {
+ if (RD->getNumVBases() > 0) {
+ auto DirectParent = ObjectAccessPath.back();
+ auto *DirectFieldParent = cast<const FieldDecl *>(DirectParent);
+ SemaSYCLRef.Diag(DirectFieldParent->getLocation(),
+ diag::err_sycl_kernel_param_has_vbase)
+ << DirectFieldParent->getType();
+ emitObjectAccessPathNotes();
+
+ IsValid = false;
+ return false;
+ }
+ }
// Warn about pointer parameters in SYCL kernels if non-portable SYCL
// warnings are enabled.
if (Ty->isPointerType()) {
diff --git a/clang/test/SemaSYCL/sycl-kernel-param-restrictions.cpp b/clang/test/SemaSYCL/sycl-kernel-param-restrictions.cpp
index f93cc17d72d89..5cbf6ce472ebc 100644
--- a/clang/test/SemaSYCL/sycl-kernel-param-restrictions.cpp
+++ b/clang/test/SemaSYCL/sycl-kernel-param-restrictions.cpp
@@ -151,33 +151,6 @@ void test(int AS) {
} // namespace badref4
-// Test virtual bases.
-// FIXME: explicitly diagnose virtual bases within kernel parameters.
-namespace badref5 {
-// Kernel entry point template definition.
-template<typename KNT, typename T>
-[[clang::sycl_kernel_entry_point(KNT)]]
-void kernel_single_task(T t) {} //expected-note {{within parameter 't' of type 'badref5::Derived' declared here}}
-
-class Base { // expected-note {{within field of type 'Base' declared here}}}
- int &data; // expected-error {{'int &' cannot be used as the type of a kernel parameter}}
-public:
- Base(int &a) : data(a) {}
-};
-
-class Derived : virtual Base { // expected-note {{within base class of type 'Base' declared here}}
-public:
- Derived(int &a) : Base(a) {}
-
-};
-
-void test() {
- int p = 0;
- kernel_single_task<class KN<12>>(Derived{p});
- // expected-note-re at -1 {{in instantiation of function template specialization 'badref5::kernel_single_task<KN<{{[0-9]+}}>, {{.*}}>' requested here}}
-}
-} // namespace badref5
-
// Check that a struct that hold a reference and captured by reference by lambda
// kernel object is diagnosed correctly.
namespace badref6 {
@@ -316,7 +289,37 @@ class Kernel {
void test() {
int *ptr;
kernel_single_task<class KN<24>>(Kernel()); // DOESNT DETECT
- kernel_single_task<class KN<25>>([=]{ (void)ptr; }); // DOESNT DETECT
+ kernel_single_task<class KN<25>>([=]{ (void)ptr; });
}
-} // namespace nonportable1
\ No newline at end of file
+} // namespace nonportable1
+
+// Test virtual bases.
+// FIXME: explicitly diagnose virtual bases within kernel parameters.
+namespace badref5 {
+// Kernel entry point template definition.
+template<typename KNT, typename T>
+[[clang::sycl_kernel_entry_point(KNT)]]
+void kernel_single_task(T t) {} //expected-note {{within parameter 't' of type 'badref5::Derived' declared here}}
+
+class Base { // expected-note {{within field of type 'Base' declared here}}}
+ int &data; // expected-error {{'int &' cannot be used as the type of a kernel parameter}}
+public:
+ Base(int &a) : data(a) {}
+};
+
+class Derived : virtual Base { // expected-note {{within base class of type 'Base' declared here}}
+public:
+ Derived(int &a) : Base(a) {}
+
+};
+
+void test() {
+ int p = 0;
+ kernel_single_task<class KN<12>>(Derived{p});
+ // expected-note-re at -1 {{in instantiation of function template specialization 'badref5::kernel_single_task<KN<{{[0-9]+}}>, {{.*}}>' requested here}}
+
+ Derived d{p};
+ kernel_single_task<class KN<30>>([=]{ (void)d; });
+}
+} // namespace badref5
>From 34521226c5b70a9ab21eeabe93b2371ae7fc4b66 Mon Sep 17 00:00:00 2001
From: "Li, Ian" <ian.li at intel.com>
Date: Thu, 9 Jul 2026 15:10:19 -0700
Subject: [PATCH 03/11] update handling of object path
---
.../clang/Basic/DiagnosticSemaKinds.td | 8 +-
clang/lib/Sema/SemaSYCL.cpp | 53 +++---
.../sycl-kernel-param-restrictions.cpp | 164 ++++++++++++------
3 files changed, 148 insertions(+), 77 deletions(-)
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index acef5af0b34f8..bd59d17b08b12 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -13514,12 +13514,16 @@ def err_sycl_special_type_num_init_method : Error<
"method defined">;
def err_sycl_device_invalid_target : Error<
"%0 is not a supported SYCL device target">;
-def warn_sycl_kernel_has_ptr_param : Warning<
- "pointers parameters in SYCL kernels must point to device-accessible memory, "
+def warn_sycl_kernel_param_has_ptr: Warning<
+ "pointer parameters in SYCL kernels must point to device-accessible memory, "
"i.e. the USM">,
InGroup<NonPortableSYCL>, DefaultIgnore;
def err_sycl_kernel_param_has_vbase : Error<
"%0 inherits virtual base classes and cannot be used as a SYCL kernel parameter">;
+def err_sycl_kernel_param_has_fam : Error<
+ "%0 contains a flexible array member and cannot be used as a SYCL kernel parameter">;
+def err_sycl_kernel_param_has_vmt : Error<
+ "%0 is a variably modified type and cannot be used as a SYCL kernel parameter">;
// SYCL external attribute diagnostics
def err_sycl_external_invalid_linkage : Error<
diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp
index 88b6aefa187f9..3eaaacefe396b 100644
--- a/clang/lib/Sema/SemaSYCL.cpp
+++ b/clang/lib/Sema/SemaSYCL.cpp
@@ -674,6 +674,16 @@ class KernelParamsChecker : public ConstSubobjectVisitor<KernelParamsChecker> {
const FieldDecl *>;
SmallVector<ObjectAccess, 4> ObjectAccessPath;
+ std::pair<QualType, SourceLocation> getObjectAccessDebugInfo(ObjectAccess o) {
+ if (auto *PVD = dyn_cast<const ParmVarDecl *>(o))
+ return std::pair{PVD->getType(), PVD->getLocation()};
+ else if (auto *FD = dyn_cast<const FieldDecl *>(o))
+ return std::pair{FD->getType(), FD->getLocation()};
+ else if (auto *BS = dyn_cast<const CXXBaseSpecifier *>(o))
+ return std::pair{BS->getType(), BS->getBaseTypeLoc()};
+ llvm_unreachable("Unexpected type in ObjectAccess");
+ }
+
void emitObjectAccessPathNotes() {
for (auto Parent : llvm::reverse(ObjectAccessPath)) {
if (auto *FD = Parent.dyn_cast<const FieldDecl *>()) {
@@ -751,29 +761,34 @@ class KernelParamsChecker : public ConstSubobjectVisitor<KernelParamsChecker> {
IsValid = false;
return false;
}
-
- Ty.dump();
- if (Ty->isAtomicType() ||
- Ty->isStructureTypeWithFlexibleArrayMember() ||
- Ty->isVariablyModifiedType()) {
-
- auto DirectParent = ObjectAccessPath.back();
- auto *DirectFieldParent = cast<const FieldDecl *>(DirectParent);
- SemaSYCLRef.Diag(DirectFieldParent->getLocation(),
- diag::err_bad_kernel_param_type)
- << DirectFieldParent->getType();
+ if (Ty->isAtomicType()) {
+ const auto& [Type, Loc] = getObjectAccessDebugInfo(ObjectAccessPath.back());
+ SemaSYCLRef.Diag(Loc, diag::err_bad_kernel_param_type) << Type;
emitObjectAccessPathNotes();
IsValid = false;
return false;
}
+ if (Ty->isVariablyModifiedType()) {
+ const auto& [Type, Loc] = getObjectAccessDebugInfo(ObjectAccessPath.back());
+ SemaSYCLRef.Diag(Loc, diag::err_sycl_kernel_param_has_vmt) << Type;
+ emitObjectAccessPathNotes();
+
+ IsValid = false;
+ return false;
+ }
+ if (Ty->isStructureTypeWithFlexibleArrayMember()) {
+ const auto& [Type, Loc] = getObjectAccessDebugInfo(ObjectAccessPath.back());
+ SemaSYCLRef.Diag(Loc, diag::err_sycl_kernel_param_has_fam) << Type;
+ emitObjectAccessPathNotes();
+
+ IsValid = false;
+ return false;
+ }
if (CXXRecordDecl *RD = Ty->getAsCXXRecordDecl()) {
if (RD->getNumVBases() > 0) {
- auto DirectParent = ObjectAccessPath.back();
- auto *DirectFieldParent = cast<const FieldDecl *>(DirectParent);
- SemaSYCLRef.Diag(DirectFieldParent->getLocation(),
- diag::err_sycl_kernel_param_has_vbase)
- << DirectFieldParent->getType();
+ const auto& [Type, Loc] = getObjectAccessDebugInfo(ObjectAccessPath.back());
+ SemaSYCLRef.Diag(Loc, diag::err_sycl_kernel_param_has_vbase) << Type;
emitObjectAccessPathNotes();
IsValid = false;
@@ -783,10 +798,8 @@ class KernelParamsChecker : public ConstSubobjectVisitor<KernelParamsChecker> {
// Warn about pointer parameters in SYCL kernels if non-portable SYCL
// warnings are enabled.
if (Ty->isPointerType()) {
- auto DirectParent = ObjectAccessPath.back();
- auto *DirectFieldParent = cast<const FieldDecl *>(DirectParent);
- SemaSYCLRef.Diag(DirectFieldParent->getLocation(),
- diag::warn_sycl_kernel_has_ptr_param);
+ const auto& [Type, Loc] = getObjectAccessDebugInfo(ObjectAccessPath.back());
+ SemaSYCLRef.Diag(Loc, diag::warn_sycl_kernel_param_has_ptr) << Type;
emitObjectAccessPathNotes();
}
return true;
diff --git a/clang/test/SemaSYCL/sycl-kernel-param-restrictions.cpp b/clang/test/SemaSYCL/sycl-kernel-param-restrictions.cpp
index 5cbf6ce472ebc..a32c3f7c14355 100644
--- a/clang/test/SemaSYCL/sycl-kernel-param-restrictions.cpp
+++ b/clang/test/SemaSYCL/sycl-kernel-param-restrictions.cpp
@@ -1,7 +1,8 @@
-// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++17 -fsyntax-only -Wno-vla-cxx-extension -fsycl-is-host -verify %s
-// RUN: %clang_cc1 -triple spirv64 -std=c++17 -fsyntax-only -Wno-vla-cxx-extension -fsycl-is-device -verify %s
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++17 -fsyntax-only -Wnonportable-sycl -Wno-vla-cxx-extension -fsycl-is-host -verify %s
+// RUN: %clang_cc1 -triple spirv64 -std=c++17 -fsyntax-only -Wnonportable-sycl -Wno-vla-cxx-extension -fsycl-is-device -verify %s
+
+// TODO conditionally toggle Wnonportable-sycl
-// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++17 -fsyntax-only -Wnonportable-sycl -Wno-vla-cxx-extension -fsycl-is-host -verify=nonportable %s
// A unique kernel name type is required for each declared kernel entry point.
template<int, int = 0> struct KN;
@@ -192,123 +193,171 @@ void test() {
#include <stdatomic.h>
// Check for atomic parameters and subobjects.
-namespace badref8 {
+namespace atomic1 {
// Kernel entry point template definition.
template<typename KNT, typename T>
[[clang::sycl_kernel_entry_point(KNT)]]
-void kernel_single_task(T t) {}
+void kernel_single_task(T t) {} // expected-note-re {{within parameter 't' of type '(lambda at {{.*}})' declared here}}
+ // expected-note-re at -1 {{within parameter 't' of type '(lambda at {{.*}})' declared here}}
+ // expected-note-re at -2 {{within parameter 't' of type '(lambda at {{.*}})' declared here}}
+ // expected-note-re at -3 {{within parameter 't' of type '(lambda at {{.*}})' declared here}}
+ // expected-note at -4 {{within parameter 't' of type 'atomic1::Kernel' declared here}}
-struct S {
+struct Sa {
int a;
- _Atomic int b;
+ _Atomic int b; // expected-error {{'_Atomic(int)' cannot be used as the type of a kernel parameter}}
+ // expected-note at -3 {{within field of type 'Sa' declared here}}
+ // expected-error at -2 {{'_Atomic(int)' cannot be used as the type of a kernel parameter}}
+ // expected-note at -5 {{within field of type 'Sa' declared here}}
+ // expected-error at -4 {{'_Atomic(int)' cannot be used as the type of a kernel parameter}}
+ // expected-note at -7 {{within field of type 'Sa' declared here}}
};
class Kernel {
- S data{1, 2};
+ Sa data{1, 2}; // expected-note at -1 {{within field of type 'Kernel' declared here}}
public:
void operator()() { }
};
void test() {
_Atomic int a = 0;
- // TODO _Atomic(int) a
- S s{1, 2};
- S arr[] = {s, s};
+ _Atomic(int) b = 2;
+ Sa s{1, 2};
+ Sa arr[] = {s, s};
kernel_single_task<class KN<15>>([=]{ (void)a; });
- kernel_single_task<class KN<16>>([=]{ (void)s; });
- kernel_single_task<class KN<17>>([=]{ (void)arr; });
- kernel_single_task<class KN<18>>(Kernel());
- // kernel_single_task<class KN<17>>([](S s) { (void)s; }); // DOESNT DETECT
+ // expected-error at -1 {{'_Atomic(int)' cannot be used as the type of a kernel parameter}}
+ // expected-note-re at -2 {{in instantiation of function template specialization 'atomic1::kernel_single_task<KN<{{[0-9]+}}>, {{.*}}>' requested here}}
+ // expected-note at -3 {{within capture 'a' of lambda expression here}}
+ kernel_single_task<class KN<16>>([=]{ (void)b; });
+ // expected-error at -1 {{'_Atomic(int)' cannot be used as the type of a kernel parameter}}
+ // expected-note-re at -2 {{in instantiation of function template specialization 'atomic1::kernel_single_task<KN<{{[0-9]+}}>, {{.*}}>' requested here}}
+ // expected-note at -3 {{within capture 'b' of lambda expression here}}
+ kernel_single_task<class KN<17>>([=]{ (void)s; });
+ // expected-note-re at -1 {{in instantiation of function template specialization 'atomic1::kernel_single_task<KN<{{[0-9]+}}>, {{.*}}>' requested here}}
+ // expected-note at -2 {{within capture 's' of lambda expression here}}
+ kernel_single_task<class KN<18>>([=]{ (void)arr; });
+ // expected-note-re at -1 {{in instantiation of function template specialization 'atomic1::kernel_single_task<KN<{{[0-9]+}}>, {{.*}}>' requested here}}
+ // expected-note at -2 {{within capture 'arr' of lambda expression here}}
+ kernel_single_task<class KN<19>>(Kernel());
+ // expected-note-re at -1 {{in instantiation of function template specialization 'atomic1::kernel_single_task<KN<{{[0-9]+}}>, {{.*}}>' requested here}}
}
-} // namespace badref8
-
+} // namespace atomic1
// Check for flexible array members -- would not be copyable to device
-namespace badref9 {
+namespace fam1 {
// Kernel entry point template definition.
template<typename KNT, typename T>
[[clang::sycl_kernel_entry_point(KNT)]]
-void kernel_single_task(T t) {}
+void kernel_single_task(T t) {} // expected-note {{within parameter 't' of type 'fam1::Kernel' declared here}}
struct FAM {
int a;
- int[] b;
+ int b[];
};
-class Kernel {
- FAM fam;
+class Kernel { // expected-note {{within field of type 'Kernel' declared here}}
+ FAM fam; // expected-error {{'FAM' contains a flexible array member and cannot be used as a SYCL kernel parameter}}
public:
- void operator()() { }
+ void operator()() { (void)fam; }
};
void test() {
FAM fam;
- kernel_single_task<class KN<19>>([=]{ (void)fam; }); // DOESNT DETECT
- kernel_single_task<class KN<20>>(Kernel());
+ //kernel_single_task<class KN<40>>([=]{ (void)fam; }); // Doesn't detect, FAM might not be capturable
+ //kernel_single_task<class KN<40>>([](FAM f){ (void)f; return 1; }(fam)); // DOESNT DETECT
+ //kernel_single_task<class KN<20>>([](FAM f){ return f; }(fam)); // not the result I'm looking for
+ kernel_single_task<class KN<21>>(Kernel());
+ // expected-note-re at -1 {{in instantiation of function template specialization 'fam1::kernel_single_task<KN<{{[0-9]+}}>, {{.*}}>' requested here}}
}
-} // namespace badref9
+} // namespace fam1
// Check for variable member array -- would not be copyable to device
-namespace badref10 {
+namespace vmt1 {
// Kernel entry point template definition.
template<typename KNT, typename T>
[[clang::sycl_kernel_entry_point(KNT)]]
-void kernel_single_task(T t) {}
-
-class Kernel {
- int len;
-public:
- Kernel(int l, int vmt[n]) : len(l) {}
- void operator()(int n, int vmt[n]) { (void)vmt; }
-};
+void kernel_single_task(T t) {} // expected-note-re {{within parameter 't' of type '(lambda at {{.*}})' declared here}}
void test() {
int n;
int Vmt[n];
- kernel_single_task<class KN<21>>([=](int n, int vmt[n]) { (void)vmt; }); // DOESNT DETECT
- kernel_single_task<class KN<22>>(Kernel()); // DOESNT DETECT
+ //kernel_single_task<class KN<22>>([](int n, int vmt[n]){ (void)vmt; }(n, Vmt)); // DOESNT DETECT
kernel_single_task<class KN<23>>([=]{ (void)Vmt; });
+ // expected-error at -1 {{'int[n]' is a variably modified type and cannot be used as a SYCL kernel parameter}}
+ // expected-note-re at -2 {{in instantiation of function template specialization 'vmt1::kernel_single_task<KN<{{[0-9]+}}>, {{.*}}>' requested here}}
+ // expected-note at -3 {{within capture 'Vmt' of lambda expression here}}
+ // expected-error at -4 {{variable-sized object may not be initialized}}
}
-} // namespace badref10
-
+} // namespace vmt1
+
// Check for pointer parameters
namespace nonportable1 {
// Kernel entry point template definition.
template<typename KNT, typename T>
[[clang::sycl_kernel_entry_point(KNT)]]
-void kernel_single_task(T t) {}
+void kernel_single_task(T t) {} // expected-note-re {{within parameter 't' of type '(lambda at {{.*}})' declared here}}
+ // expected-note-re at -1 {{within parameter 't' of type '(lambda at {{.*}})' declared here}}
+ // expected-note-re at -2 {{within parameter 't' of type '(lambda at {{.*}})' declared here}}
+ // expected-note-re at -3 {{within parameter 't' of type '(lambda at {{.*}})' declared here}}
-class Kernel {
+struct S { // expected-note {{within field of type 'S' declared here}}
+ // expected-note at -1 {{within field of type 'S' declared here}}
+ int *ptr;
+ // expected-warning at -1 {{pointer parameters in SYCL kernels must point to device-accessible memory, i.e. the USM}}
+ // expected-warning at -2 {{pointer parameters in SYCL kernels must point to device-accessible memory, i.e. the USM}}
+};
+
+class C { // expected-note {{within field of type 'C' declared here}}
+private:
+ int *ptr;
+ // expected-warning at -1 {{pointer parameters in SYCL kernels must point to device-accessible memory, i.e. the USM}}
+ // TODO double-check this warning actually tells me what field is the problem
public:
- void operator()(int *ptr) { (void)ptr; }
+ C(int *p) : ptr(p) {}
};
void test() {
int *ptr;
- kernel_single_task<class KN<24>>(Kernel()); // DOESNT DETECT
kernel_single_task<class KN<25>>([=]{ (void)ptr; });
+ // expected-warning at -1 {{pointer parameters in SYCL kernels must point to device-accessible memory, i.e. the USM}}
+ // expected-note-re at -2 {{in instantiation of function template specialization 'nonportable1::kernel_single_task<KN<{{[0-9]+}}>, {{.*}}>' requested here}}
+ // expected-note at -3 {{within capture 'ptr' of lambda expression here}}
+
+ S s{ptr};
+ kernel_single_task<class KN<26>>([=]{ (void)s; });
+ // expected-note-re at -1 {{in instantiation of function template specialization 'nonportable1::kernel_single_task<KN<{{[0-9]+}}>, {{.*}}>' requested here}}
+ // expected-note at -2 {{within capture 's' of lambda expression here}}
+
+ C c{ptr};
+ kernel_single_task<class KN<27>>([=]{ (void)c; });
+ // expected-note-re at -1 {{in instantiation of function template specialization 'nonportable1::kernel_single_task<KN<{{[0-9]+}}>, {{.*}}>' requested here}}
+ // expected-note at -2 {{within capture 'c' of lambda expression here}}
+
+ S arr[3] = {{ptr}, {ptr}, {ptr}};
+ kernel_single_task<class KN<28>>([=]{ (void)arr; });
+ // expected-note-re at -1 {{in instantiation of function template specialization 'nonportable1::kernel_single_task<KN<{{[0-9]+}}>, {{.*}}>' requested here}}
+ // expected-note at -2 {{within capture 'arr' of lambda expression here}}
}
} // namespace nonportable1
-// Test virtual bases.
-// FIXME: explicitly diagnose virtual bases within kernel parameters.
-namespace badref5 {
+// Check for virtual bases
+namespace vbase1 {
// Kernel entry point template definition.
template<typename KNT, typename T>
[[clang::sycl_kernel_entry_point(KNT)]]
-void kernel_single_task(T t) {} //expected-note {{within parameter 't' of type 'badref5::Derived' declared here}}
+void kernel_single_task(T t) {} // expected-note-re {{within parameter 't' of type '(lambda at {{.*}})' declared here}}
-class Base { // expected-note {{within field of type 'Base' declared here}}}
- int &data; // expected-error {{'int &' cannot be used as the type of a kernel parameter}}
+class Base {
+ int &data;
public:
Base(int &a) : data(a) {}
};
-class Derived : virtual Base { // expected-note {{within base class of type 'Base' declared here}}
+class Derived : virtual Base {
public:
Derived(int &a) : Base(a) {}
@@ -316,10 +365,15 @@ class Derived : virtual Base { // expected-note {{within base class of type 'Bas
void test() {
int p = 0;
- kernel_single_task<class KN<12>>(Derived{p});
- // expected-note-re at -1 {{in instantiation of function template specialization 'badref5::kernel_single_task<KN<{{[0-9]+}}>, {{.*}}>' requested here}}
-
Derived d{p};
- kernel_single_task<class KN<30>>([=]{ (void)d; });
+ kernel_single_task<class KN<29>>([=]{ (void)d; });
+ // expected-error at -1 {{'Derived' inherits virtual base classes and cannot be used as a SYCL kernel parameter}}
+ // expected-note-re at -2 {{in instantiation of function template specialization 'vbase1::kernel_single_task<KN<{{[0-9]+}}>, {{.*}}>' requested here}}
+ // expected-note at -3 {{within capture 'd' of lambda expression here}}
+
+ //kernel_single_task<class KN<30>>([](Derived d){ return d; }(d)); // not sure if this gives me what I actually want
+ // xpected-error at -1 {{'vbase1::Derived' inherits virtual base classes and cannot be used as a SYCL kernel parameter}}
+ // xpected-note-re at -2 {{in instantiation of function template specialization 'vbase1::kernel_single_task<KN<{{[0-9]+}}>, {{.*}}>' requested here}}
+ // xpected-note at -3 {{within capture 'd' of lambda expression here}}
}
-} // namespace badref5
+} // namespace vbase1
>From 8be6ac0148757871460c5ec8759261d41055e0ec Mon Sep 17 00:00:00 2001
From: "Li, Ian" <ian.li at intel.com>
Date: Fri, 10 Jul 2026 10:08:14 -0700
Subject: [PATCH 04/11] Address issues with test coverage
---
clang/lib/Sema/SemaSYCL.cpp | 13 +++++--------
.../SemaSYCL/sycl-kernel-param-restrictions.cpp | 13 +++++++------
2 files changed, 12 insertions(+), 14 deletions(-)
diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp
index 3eaaacefe396b..a52a412fc174b 100644
--- a/clang/lib/Sema/SemaSYCL.cpp
+++ b/clang/lib/Sema/SemaSYCL.cpp
@@ -760,32 +760,28 @@ class KernelParamsChecker : public ConstSubobjectVisitor<KernelParamsChecker> {
// invalid use of a reference.
IsValid = false;
return false;
- }
- if (Ty->isAtomicType()) {
+ } else if (Ty->isAtomicType()) {
const auto& [Type, Loc] = getObjectAccessDebugInfo(ObjectAccessPath.back());
SemaSYCLRef.Diag(Loc, diag::err_bad_kernel_param_type) << Type;
emitObjectAccessPathNotes();
IsValid = false;
return false;
- }
- if (Ty->isVariablyModifiedType()) {
+ } else if (Ty->isVariablyModifiedType()) {
const auto& [Type, Loc] = getObjectAccessDebugInfo(ObjectAccessPath.back());
SemaSYCLRef.Diag(Loc, diag::err_sycl_kernel_param_has_vmt) << Type;
emitObjectAccessPathNotes();
IsValid = false;
return false;
- }
- if (Ty->isStructureTypeWithFlexibleArrayMember()) {
+ } else if (Ty->isStructureTypeWithFlexibleArrayMember()) {
const auto& [Type, Loc] = getObjectAccessDebugInfo(ObjectAccessPath.back());
SemaSYCLRef.Diag(Loc, diag::err_sycl_kernel_param_has_fam) << Type;
emitObjectAccessPathNotes();
IsValid = false;
return false;
- }
- if (CXXRecordDecl *RD = Ty->getAsCXXRecordDecl()) {
+ } else if (CXXRecordDecl *RD = Ty->getAsCXXRecordDecl()) {
if (RD->getNumVBases() > 0) {
const auto& [Type, Loc] = getObjectAccessDebugInfo(ObjectAccessPath.back());
SemaSYCLRef.Diag(Loc, diag::err_sycl_kernel_param_has_vbase) << Type;
@@ -795,6 +791,7 @@ class KernelParamsChecker : public ConstSubobjectVisitor<KernelParamsChecker> {
return false;
}
}
+
// Warn about pointer parameters in SYCL kernels if non-portable SYCL
// warnings are enabled.
if (Ty->isPointerType()) {
diff --git a/clang/test/SemaSYCL/sycl-kernel-param-restrictions.cpp b/clang/test/SemaSYCL/sycl-kernel-param-restrictions.cpp
index a32c3f7c14355..493c1843dca72 100644
--- a/clang/test/SemaSYCL/sycl-kernel-param-restrictions.cpp
+++ b/clang/test/SemaSYCL/sycl-kernel-param-restrictions.cpp
@@ -264,16 +264,14 @@ class Kernel { // expected-note {{within field of type 'Kernel' declared here}}
void test() {
FAM fam;
- //kernel_single_task<class KN<40>>([=]{ (void)fam; }); // Doesn't detect, FAM might not be capturable
- //kernel_single_task<class KN<40>>([](FAM f){ (void)f; return 1; }(fam)); // DOESNT DETECT
- //kernel_single_task<class KN<20>>([](FAM f){ return f; }(fam)); // not the result I'm looking for
- kernel_single_task<class KN<21>>(Kernel());
+ // Flexible array members cannot be captured in a lambda, thus no lambda tests are provided.
+ kernel_single_task<class KN<21>>(Kernel{});
// expected-note-re at -1 {{in instantiation of function template specialization 'fam1::kernel_single_task<KN<{{[0-9]+}}>, {{.*}}>' requested here}}
}
} // namespace fam1
-// Check for variable member array -- would not be copyable to device
+// Check for variably modified types -- would not be copyable to device
namespace vmt1 {
// Kernel entry point template definition.
template<typename KNT, typename T>
@@ -283,7 +281,10 @@ void kernel_single_task(T t) {} // expected-note-re {{within parameter 't' of ty
void test() {
int n;
int Vmt[n];
- //kernel_single_task<class KN<22>>([](int n, int vmt[n]){ (void)vmt; }(n, Vmt)); // DOESNT DETECT
+ // VLAs as parameters are lowered to a pointer, preventing test cases with VLAs
+ // as normal lambda parameters. The below test case uses technically invalid
+ // code, but preserves the VLA in the lambda.
+ // As a result, suppress "variable-sized object may not be initialized" is needed.
kernel_single_task<class KN<23>>([=]{ (void)Vmt; });
// expected-error at -1 {{'int[n]' is a variably modified type and cannot be used as a SYCL kernel parameter}}
// expected-note-re at -2 {{in instantiation of function template specialization 'vmt1::kernel_single_task<KN<{{[0-9]+}}>, {{.*}}>' requested here}}
>From dbb30993402cdb6ca9d8a78dd560e9d9d09c77f3 Mon Sep 17 00:00:00 2001
From: "Li, Ian" <ian.li at intel.com>
Date: Fri, 10 Jul 2026 10:37:21 -0700
Subject: [PATCH 05/11] Clean up code
---
.../clang/Basic/DiagnosticSemaKinds.td | 2 +-
clang/lib/Sema/SemaSYCL.cpp | 46 ++++++++-----------
.../sycl-kernel-param-restrictions.cpp | 8 ++--
3 files changed, 24 insertions(+), 32 deletions(-)
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index bd59d17b08b12..eb28a6a4494d2 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -13515,7 +13515,7 @@ def err_sycl_special_type_num_init_method : Error<
def err_sycl_device_invalid_target : Error<
"%0 is not a supported SYCL device target">;
def warn_sycl_kernel_param_has_ptr: Warning<
- "pointer parameters in SYCL kernels must point to device-accessible memory, "
+ "pointers used in SYCL kernels must point to device-accessible memory, "
"i.e. the USM">,
InGroup<NonPortableSYCL>, DefaultIgnore;
def err_sycl_kernel_param_has_vbase : Error<
diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp
index a52a412fc174b..40ff8d35a4305 100644
--- a/clang/lib/Sema/SemaSYCL.cpp
+++ b/clang/lib/Sema/SemaSYCL.cpp
@@ -675,13 +675,13 @@ class KernelParamsChecker : public ConstSubobjectVisitor<KernelParamsChecker> {
SmallVector<ObjectAccess, 4> ObjectAccessPath;
std::pair<QualType, SourceLocation> getObjectAccessDebugInfo(ObjectAccess o) {
- if (auto *PVD = dyn_cast<const ParmVarDecl *>(o))
- return std::pair{PVD->getType(), PVD->getLocation()};
- else if (auto *FD = dyn_cast<const FieldDecl *>(o))
- return std::pair{FD->getType(), FD->getLocation()};
- else if (auto *BS = dyn_cast<const CXXBaseSpecifier *>(o))
- return std::pair{BS->getType(), BS->getBaseTypeLoc()};
- llvm_unreachable("Unexpected type in ObjectAccess");
+ if (auto *PVD = dyn_cast<const ParmVarDecl *>(o))
+ return std::pair{PVD->getType(), PVD->getLocation()};
+ else if (auto *FD = dyn_cast<const FieldDecl *>(o))
+ return std::pair{FD->getType(), FD->getLocation()};
+ else if (auto *BS = dyn_cast<const CXXBaseSpecifier *>(o))
+ return std::pair{BS->getType(), BS->getBaseTypeLoc()};
+ llvm_unreachable("Unexpected type in ObjectAccess");
}
void emitObjectAccessPathNotes() {
@@ -738,6 +738,12 @@ class KernelParamsChecker : public ConstSubobjectVisitor<KernelParamsChecker> {
// Returns true if subobjects should be visited and false otherwise.
bool checkType(QualType Ty) {
+ auto emitDiagnostic = [this](clang::diag::kind mesg) {
+ const auto &[Type, Loc] =
+ getObjectAccessDebugInfo(ObjectAccessPath.back());
+ SemaSYCLRef.Diag(Loc, mesg) << Type;
+ emitObjectAccessPathNotes();
+ };
if (Ty->isReferenceType()) {
auto DirectParent = ObjectAccessPath.back();
// Reference cannot be a base, so just assume we came via a FieldDecl.
@@ -761,43 +767,29 @@ class KernelParamsChecker : public ConstSubobjectVisitor<KernelParamsChecker> {
IsValid = false;
return false;
} else if (Ty->isAtomicType()) {
- const auto& [Type, Loc] = getObjectAccessDebugInfo(ObjectAccessPath.back());
- SemaSYCLRef.Diag(Loc, diag::err_bad_kernel_param_type) << Type;
- emitObjectAccessPathNotes();
-
+ emitDiagnostic(diag::err_bad_kernel_param_type);
IsValid = false;
return false;
} else if (Ty->isVariablyModifiedType()) {
- const auto& [Type, Loc] = getObjectAccessDebugInfo(ObjectAccessPath.back());
- SemaSYCLRef.Diag(Loc, diag::err_sycl_kernel_param_has_vmt) << Type;
- emitObjectAccessPathNotes();
-
+ emitDiagnostic(diag::err_sycl_kernel_param_has_vmt);
IsValid = false;
return false;
} else if (Ty->isStructureTypeWithFlexibleArrayMember()) {
- const auto& [Type, Loc] = getObjectAccessDebugInfo(ObjectAccessPath.back());
- SemaSYCLRef.Diag(Loc, diag::err_sycl_kernel_param_has_fam) << Type;
- emitObjectAccessPathNotes();
-
+ emitDiagnostic(diag::err_sycl_kernel_param_has_fam);
IsValid = false;
return false;
} else if (CXXRecordDecl *RD = Ty->getAsCXXRecordDecl()) {
if (RD->getNumVBases() > 0) {
- const auto& [Type, Loc] = getObjectAccessDebugInfo(ObjectAccessPath.back());
- SemaSYCLRef.Diag(Loc, diag::err_sycl_kernel_param_has_vbase) << Type;
- emitObjectAccessPathNotes();
-
+ emitDiagnostic(diag::err_sycl_kernel_param_has_vbase);
IsValid = false;
return false;
}
}
-
+
// Warn about pointer parameters in SYCL kernels if non-portable SYCL
// warnings are enabled.
if (Ty->isPointerType()) {
- const auto& [Type, Loc] = getObjectAccessDebugInfo(ObjectAccessPath.back());
- SemaSYCLRef.Diag(Loc, diag::warn_sycl_kernel_param_has_ptr) << Type;
- emitObjectAccessPathNotes();
+ emitDiagnostic(diag::warn_sycl_kernel_param_has_ptr);
}
return true;
}
diff --git a/clang/test/SemaSYCL/sycl-kernel-param-restrictions.cpp b/clang/test/SemaSYCL/sycl-kernel-param-restrictions.cpp
index 493c1843dca72..c0b3d910bc7d9 100644
--- a/clang/test/SemaSYCL/sycl-kernel-param-restrictions.cpp
+++ b/clang/test/SemaSYCL/sycl-kernel-param-restrictions.cpp
@@ -307,14 +307,14 @@ void kernel_single_task(T t) {} // expected-note-re {{within parameter 't' of ty
struct S { // expected-note {{within field of type 'S' declared here}}
// expected-note at -1 {{within field of type 'S' declared here}}
int *ptr;
- // expected-warning at -1 {{pointer parameters in SYCL kernels must point to device-accessible memory, i.e. the USM}}
- // expected-warning at -2 {{pointer parameters in SYCL kernels must point to device-accessible memory, i.e. the USM}}
+ // expected-warning at -1 {{pointers used in SYCL kernels must point to device-accessible memory, i.e. the USM}}
+ // expected-warning at -2 {{pointers used in SYCL kernels must point to device-accessible memory, i.e. the USM}}
};
class C { // expected-note {{within field of type 'C' declared here}}
private:
int *ptr;
- // expected-warning at -1 {{pointer parameters in SYCL kernels must point to device-accessible memory, i.e. the USM}}
+ // expected-warning at -1 {{pointers used in SYCL kernels must point to device-accessible memory, i.e. the USM}}
// TODO double-check this warning actually tells me what field is the problem
public:
C(int *p) : ptr(p) {}
@@ -323,7 +323,7 @@ class C { // expected-note {{within field of type 'C' declared here}}
void test() {
int *ptr;
kernel_single_task<class KN<25>>([=]{ (void)ptr; });
- // expected-warning at -1 {{pointer parameters in SYCL kernels must point to device-accessible memory, i.e. the USM}}
+ // expected-warning at -1 {{pointers used in SYCL kernels must point to device-accessible memory, i.e. the USM}}
// expected-note-re at -2 {{in instantiation of function template specialization 'nonportable1::kernel_single_task<KN<{{[0-9]+}}>, {{.*}}>' requested here}}
// expected-note at -3 {{within capture 'ptr' of lambda expression here}}
>From b2815bd778bebeb35e45e56d2be949abc204893a Mon Sep 17 00:00:00 2001
From: "Li, Ian" <ian.li at intel.com>
Date: Fri, 10 Jul 2026 11:33:19 -0700
Subject: [PATCH 06/11] remove VMT checks, split nonportable lit test into
separate run
---
.../clang/Basic/DiagnosticSemaKinds.td | 2 -
clang/lib/Sema/SemaSYCL.cpp | 4 --
.../sycl-kernel-param-restrictions.cpp | 70 ++++++-------------
3 files changed, 23 insertions(+), 53 deletions(-)
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index eb28a6a4494d2..784bde5d68f08 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -13522,8 +13522,6 @@ def err_sycl_kernel_param_has_vbase : Error<
"%0 inherits virtual base classes and cannot be used as a SYCL kernel parameter">;
def err_sycl_kernel_param_has_fam : Error<
"%0 contains a flexible array member and cannot be used as a SYCL kernel parameter">;
-def err_sycl_kernel_param_has_vmt : Error<
- "%0 is a variably modified type and cannot be used as a SYCL kernel parameter">;
// SYCL external attribute diagnostics
def err_sycl_external_invalid_linkage : Error<
diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp
index 40ff8d35a4305..47e41d81b9a68 100644
--- a/clang/lib/Sema/SemaSYCL.cpp
+++ b/clang/lib/Sema/SemaSYCL.cpp
@@ -770,10 +770,6 @@ class KernelParamsChecker : public ConstSubobjectVisitor<KernelParamsChecker> {
emitDiagnostic(diag::err_bad_kernel_param_type);
IsValid = false;
return false;
- } else if (Ty->isVariablyModifiedType()) {
- emitDiagnostic(diag::err_sycl_kernel_param_has_vmt);
- IsValid = false;
- return false;
} else if (Ty->isStructureTypeWithFlexibleArrayMember()) {
emitDiagnostic(diag::err_sycl_kernel_param_has_fam);
IsValid = false;
diff --git a/clang/test/SemaSYCL/sycl-kernel-param-restrictions.cpp b/clang/test/SemaSYCL/sycl-kernel-param-restrictions.cpp
index c0b3d910bc7d9..120b00e1fc41f 100644
--- a/clang/test/SemaSYCL/sycl-kernel-param-restrictions.cpp
+++ b/clang/test/SemaSYCL/sycl-kernel-param-restrictions.cpp
@@ -1,8 +1,7 @@
-// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++17 -fsyntax-only -Wnonportable-sycl -Wno-vla-cxx-extension -fsycl-is-host -verify %s
-// RUN: %clang_cc1 -triple spirv64 -std=c++17 -fsyntax-only -Wnonportable-sycl -Wno-vla-cxx-extension -fsycl-is-device -verify %s
-
-// TODO conditionally toggle Wnonportable-sycl
-
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++17 -fsyntax-only -Wno-vla-cxx-extension -fsycl-is-host -verify=expected %s
+// RUN: %clang_cc1 -triple spirv64 -std=c++17 -fsyntax-only -Wno-vla-cxx-extension -fsycl-is-device -verify=expected %s
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++17 -fsyntax-only -Wnonportable-sycl -Wno-vla-cxx-extension -fsycl-is-host -verify=expected,nonportable %s
+// RUN: %clang_cc1 -triple spirv64 -std=c++17 -fsyntax-only -Wnonportable-sycl -Wno-vla-cxx-extension -fsycl-is-device -verify=expected,nonportable %s
// A unique kernel name type is required for each declared kernel entry point.
template<int, int = 0> struct KN;
@@ -271,50 +270,27 @@ void test() {
} // namespace fam1
-// Check for variably modified types -- would not be copyable to device
-namespace vmt1 {
-// Kernel entry point template definition.
-template<typename KNT, typename T>
-[[clang::sycl_kernel_entry_point(KNT)]]
-void kernel_single_task(T t) {} // expected-note-re {{within parameter 't' of type '(lambda at {{.*}})' declared here}}
-
-void test() {
- int n;
- int Vmt[n];
- // VLAs as parameters are lowered to a pointer, preventing test cases with VLAs
- // as normal lambda parameters. The below test case uses technically invalid
- // code, but preserves the VLA in the lambda.
- // As a result, suppress "variable-sized object may not be initialized" is needed.
- kernel_single_task<class KN<23>>([=]{ (void)Vmt; });
- // expected-error at -1 {{'int[n]' is a variably modified type and cannot be used as a SYCL kernel parameter}}
- // expected-note-re at -2 {{in instantiation of function template specialization 'vmt1::kernel_single_task<KN<{{[0-9]+}}>, {{.*}}>' requested here}}
- // expected-note at -3 {{within capture 'Vmt' of lambda expression here}}
- // expected-error at -4 {{variable-sized object may not be initialized}}
-}
-
-} // namespace vmt1
-
// Check for pointer parameters
namespace nonportable1 {
// Kernel entry point template definition.
template<typename KNT, typename T>
[[clang::sycl_kernel_entry_point(KNT)]]
-void kernel_single_task(T t) {} // expected-note-re {{within parameter 't' of type '(lambda at {{.*}})' declared here}}
- // expected-note-re at -1 {{within parameter 't' of type '(lambda at {{.*}})' declared here}}
- // expected-note-re at -2 {{within parameter 't' of type '(lambda at {{.*}})' declared here}}
- // expected-note-re at -3 {{within parameter 't' of type '(lambda at {{.*}})' declared here}}
+void kernel_single_task(T t) {} // nonportable-note-re {{within parameter 't' of type '(lambda at {{.*}})' declared here}}
+ // nonportable-note-re at -1 {{within parameter 't' of type '(lambda at {{.*}})' declared here}}
+ // nonportable-note-re at -2 {{within parameter 't' of type '(lambda at {{.*}})' declared here}}
+ // nonportable-note-re at -3 {{within parameter 't' of type '(lambda at {{.*}})' declared here}}
-struct S { // expected-note {{within field of type 'S' declared here}}
- // expected-note at -1 {{within field of type 'S' declared here}}
+struct S { // nonportable-note {{within field of type 'S' declared here}}
+ // nonportable-note at -1 {{within field of type 'S' declared here}}
int *ptr;
- // expected-warning at -1 {{pointers used in SYCL kernels must point to device-accessible memory, i.e. the USM}}
- // expected-warning at -2 {{pointers used in SYCL kernels must point to device-accessible memory, i.e. the USM}}
+ // nonportable-warning at -1 {{pointers used in SYCL kernels must point to device-accessible memory, i.e. the USM}}
+ // nonportable-warning at -2 {{pointers used in SYCL kernels must point to device-accessible memory, i.e. the USM}}
};
-class C { // expected-note {{within field of type 'C' declared here}}
+class C { // nonportable-note {{within field of type 'C' declared here}}
private:
int *ptr;
- // expected-warning at -1 {{pointers used in SYCL kernels must point to device-accessible memory, i.e. the USM}}
+ // nonportable-warning at -1 {{pointers used in SYCL kernels must point to device-accessible memory, i.e. the USM}}
// TODO double-check this warning actually tells me what field is the problem
public:
C(int *p) : ptr(p) {}
@@ -323,24 +299,24 @@ class C { // expected-note {{within field of type 'C' declared here}}
void test() {
int *ptr;
kernel_single_task<class KN<25>>([=]{ (void)ptr; });
- // expected-warning at -1 {{pointers used in SYCL kernels must point to device-accessible memory, i.e. the USM}}
- // expected-note-re at -2 {{in instantiation of function template specialization 'nonportable1::kernel_single_task<KN<{{[0-9]+}}>, {{.*}}>' requested here}}
- // expected-note at -3 {{within capture 'ptr' of lambda expression here}}
+ // nonportable-warning at -1 {{pointers used in SYCL kernels must point to device-accessible memory, i.e. the USM}}
+ // nonportable-note-re at -2 {{in instantiation of function template specialization 'nonportable1::kernel_single_task<KN<{{[0-9]+}}>, {{.*}}>' requested here}}
+ // nonportable-note at -3 {{within capture 'ptr' of lambda expression here}}
S s{ptr};
kernel_single_task<class KN<26>>([=]{ (void)s; });
- // expected-note-re at -1 {{in instantiation of function template specialization 'nonportable1::kernel_single_task<KN<{{[0-9]+}}>, {{.*}}>' requested here}}
- // expected-note at -2 {{within capture 's' of lambda expression here}}
+ // nonportable-note-re at -1 {{in instantiation of function template specialization 'nonportable1::kernel_single_task<KN<{{[0-9]+}}>, {{.*}}>' requested here}}
+ // nonportable-note at -2 {{within capture 's' of lambda expression here}}
C c{ptr};
kernel_single_task<class KN<27>>([=]{ (void)c; });
- // expected-note-re at -1 {{in instantiation of function template specialization 'nonportable1::kernel_single_task<KN<{{[0-9]+}}>, {{.*}}>' requested here}}
- // expected-note at -2 {{within capture 'c' of lambda expression here}}
+ // nonportable-note-re at -1 {{in instantiation of function template specialization 'nonportable1::kernel_single_task<KN<{{[0-9]+}}>, {{.*}}>' requested here}}
+ // nonportable-note at -2 {{within capture 'c' of lambda expression here}}
S arr[3] = {{ptr}, {ptr}, {ptr}};
kernel_single_task<class KN<28>>([=]{ (void)arr; });
- // expected-note-re at -1 {{in instantiation of function template specialization 'nonportable1::kernel_single_task<KN<{{[0-9]+}}>, {{.*}}>' requested here}}
- // expected-note at -2 {{within capture 'arr' of lambda expression here}}
+ // nonportable-note-re at -1 {{in instantiation of function template specialization 'nonportable1::kernel_single_task<KN<{{[0-9]+}}>, {{.*}}>' requested here}}
+ // nonportable-note at -2 {{within capture 'arr' of lambda expression here}}
}
} // namespace nonportable1
>From e868ab9f789f6ff79395eca98bfd783b9e34d39a Mon Sep 17 00:00:00 2001
From: "Li, Ian" <ian.li at intel.com>
Date: Fri, 10 Jul 2026 11:38:10 -0700
Subject: [PATCH 07/11] Make formatting conform
---
clang/test/SemaSYCL/sycl-kernel-param-restrictions.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang/test/SemaSYCL/sycl-kernel-param-restrictions.cpp b/clang/test/SemaSYCL/sycl-kernel-param-restrictions.cpp
index 120b00e1fc41f..80235804b2b26 100644
--- a/clang/test/SemaSYCL/sycl-kernel-param-restrictions.cpp
+++ b/clang/test/SemaSYCL/sycl-kernel-param-restrictions.cpp
@@ -237,7 +237,7 @@ void test() {
kernel_single_task<class KN<18>>([=]{ (void)arr; });
// expected-note-re at -1 {{in instantiation of function template specialization 'atomic1::kernel_single_task<KN<{{[0-9]+}}>, {{.*}}>' requested here}}
// expected-note at -2 {{within capture 'arr' of lambda expression here}}
- kernel_single_task<class KN<19>>(Kernel());
+ kernel_single_task<class KN<19>>(Kernel{});
// expected-note-re at -1 {{in instantiation of function template specialization 'atomic1::kernel_single_task<KN<{{[0-9]+}}>, {{.*}}>' requested here}}
}
>From 0abd5060f208a3bd3188afe5c883937b52ef164f Mon Sep 17 00:00:00 2001
From: "Li, Ian" <ian.li at intel.com>
Date: Mon, 13 Jul 2026 09:50:58 -0700
Subject: [PATCH 08/11] Remove leftover todos
---
clang/test/SemaSYCL/sycl-kernel-param-restrictions.cpp | 6 ------
1 file changed, 6 deletions(-)
diff --git a/clang/test/SemaSYCL/sycl-kernel-param-restrictions.cpp b/clang/test/SemaSYCL/sycl-kernel-param-restrictions.cpp
index 80235804b2b26..52b683c017a7b 100644
--- a/clang/test/SemaSYCL/sycl-kernel-param-restrictions.cpp
+++ b/clang/test/SemaSYCL/sycl-kernel-param-restrictions.cpp
@@ -291,7 +291,6 @@ class C { // nonportable-note {{within field of type 'C' declared here}}
private:
int *ptr;
// nonportable-warning at -1 {{pointers used in SYCL kernels must point to device-accessible memory, i.e. the USM}}
- // TODO double-check this warning actually tells me what field is the problem
public:
C(int *p) : ptr(p) {}
};
@@ -347,10 +346,5 @@ void test() {
// expected-error at -1 {{'Derived' inherits virtual base classes and cannot be used as a SYCL kernel parameter}}
// expected-note-re at -2 {{in instantiation of function template specialization 'vbase1::kernel_single_task<KN<{{[0-9]+}}>, {{.*}}>' requested here}}
// expected-note at -3 {{within capture 'd' of lambda expression here}}
-
- //kernel_single_task<class KN<30>>([](Derived d){ return d; }(d)); // not sure if this gives me what I actually want
- // xpected-error at -1 {{'vbase1::Derived' inherits virtual base classes and cannot be used as a SYCL kernel parameter}}
- // xpected-note-re at -2 {{in instantiation of function template specialization 'vbase1::kernel_single_task<KN<{{[0-9]+}}>, {{.*}}>' requested here}}
- // xpected-note at -3 {{within capture 'd' of lambda expression here}}
}
} // namespace vbase1
>From 5686ff791c2d8729c0bb3b82ac9c3a3df95e98fb Mon Sep 17 00:00:00 2001
From: Ian Li <ianayl.work at gmail.com>
Date: Wed, 15 Jul 2026 13:50:27 -0400
Subject: [PATCH 09/11] Apply suggestions from code review
Co-authored-by: Tom Honermann <tom at honermann.net>
---
clang/include/clang/Basic/DiagnosticSemaKinds.td | 3 +--
clang/test/SemaSYCL/sycl-kernel-param-restrictions.cpp | 2 ++
2 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 784bde5d68f08..a78af3bb06362 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -13515,8 +13515,7 @@ def err_sycl_special_type_num_init_method : Error<
def err_sycl_device_invalid_target : Error<
"%0 is not a supported SYCL device target">;
def warn_sycl_kernel_param_has_ptr: Warning<
- "pointers used in SYCL kernels must point to device-accessible memory, "
- "i.e. the USM">,
+ "pointers used in parameters to a SYCL kernel require a device that supports Unified Shared Memory (USM)">,
InGroup<NonPortableSYCL>, DefaultIgnore;
def err_sycl_kernel_param_has_vbase : Error<
"%0 inherits virtual base classes and cannot be used as a SYCL kernel parameter">;
diff --git a/clang/test/SemaSYCL/sycl-kernel-param-restrictions.cpp b/clang/test/SemaSYCL/sycl-kernel-param-restrictions.cpp
index 52b683c017a7b..452ce7660e017 100644
--- a/clang/test/SemaSYCL/sycl-kernel-param-restrictions.cpp
+++ b/clang/test/SemaSYCL/sycl-kernel-param-restrictions.cpp
@@ -328,6 +328,8 @@ template<typename KNT, typename T>
void kernel_single_task(T t) {} // expected-note-re {{within parameter 't' of type '(lambda at {{.*}})' declared here}}
class Base {
+ // No diagnostic is issued for data because recursive subobject visitation
+ // stops once a virtual base class is found.
int &data;
public:
Base(int &a) : data(a) {}
>From 495c34617381a98e3bc7919c50faf873d534600d Mon Sep 17 00:00:00 2001
From: "Li, Ian" <ian.li at intel.com>
Date: Thu, 16 Jul 2026 13:52:44 -0700
Subject: [PATCH 10/11] Address reviewer comments
---
.../clang/Basic/DiagnosticSemaKinds.td | 15 +--
clang/lib/Sema/SemaSYCL.cpp | 52 +++++-----
.../sycl-kernel-param-restrictions.cpp | 95 ++++++++++++-------
3 files changed, 100 insertions(+), 62 deletions(-)
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index a78af3bb06362..9a355e85ce46f 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -13514,13 +13514,6 @@ def err_sycl_special_type_num_init_method : Error<
"method defined">;
def err_sycl_device_invalid_target : Error<
"%0 is not a supported SYCL device target">;
-def warn_sycl_kernel_param_has_ptr: Warning<
- "pointers used in parameters to a SYCL kernel require a device that supports Unified Shared Memory (USM)">,
- InGroup<NonPortableSYCL>, DefaultIgnore;
-def err_sycl_kernel_param_has_vbase : Error<
- "%0 inherits virtual base classes and cannot be used as a SYCL kernel parameter">;
-def err_sycl_kernel_param_has_fam : Error<
- "%0 contains a flexible array member and cannot be used as a SYCL kernel parameter">;
// SYCL external attribute diagnostics
def err_sycl_external_invalid_linkage : Error<
@@ -13581,6 +13574,14 @@ def note_sycl_kernel_launch_overload_resolution_here : Note<
def err_sycl_entry_point_device_use : Error<
"function %0 cannot be used in device code because it is declared with the"
" %1 attribute">;
+def warn_sycl_kernel_param_has_ptr: Warning<
+ "pointers used in parameters to a SYCL kernel require a device that supports Unified Shared Memory (USM)">,
+ InGroup<NonPortableSYCL>, DefaultIgnore;
+def err_sycl_kernel_bad_param_type : Error<
+ "%0 %enum_select<InvalidSYCLKernelParamReason>{"
+ "%FAM{contains a flexible array member}|"
+ "%VirtualBases{inherits virtual base classes}|"
+ "}1 and cannot be used as the type of a SYCL kernel parameter">;
def warn_cuda_maxclusterrank_sm_90 : Warning<
"maxclusterrank requires sm_90 or higher, CUDA arch provided: %0, ignoring "
diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp
index 47e41d81b9a68..b8b26588e004f 100644
--- a/clang/lib/Sema/SemaSYCL.cpp
+++ b/clang/lib/Sema/SemaSYCL.cpp
@@ -674,13 +674,19 @@ class KernelParamsChecker : public ConstSubobjectVisitor<KernelParamsChecker> {
const FieldDecl *>;
SmallVector<ObjectAccess, 4> ObjectAccessPath;
- std::pair<QualType, SourceLocation> getObjectAccessDebugInfo(ObjectAccess o) {
+ struct DiagDetails {
+ QualType Type;
+ SourceLocation Loc;
+ };
+
+ // Return diagnostics info for an 'ObjectAccess' stored on ObjectAccessPath
+ DiagDetails getObjectAccessDiagDetails(ObjectAccess o) {
if (auto *PVD = dyn_cast<const ParmVarDecl *>(o))
- return std::pair{PVD->getType(), PVD->getLocation()};
- else if (auto *FD = dyn_cast<const FieldDecl *>(o))
- return std::pair{FD->getType(), FD->getLocation()};
- else if (auto *BS = dyn_cast<const CXXBaseSpecifier *>(o))
- return std::pair{BS->getType(), BS->getBaseTypeLoc()};
+ return {PVD->getType(), PVD->getLocation()};
+ if (auto *FD = dyn_cast<const FieldDecl *>(o))
+ return {FD->getType(), FD->getLocation()};
+ if (auto *BS = dyn_cast<const CXXBaseSpecifier *>(o))
+ return {BS->getType(), BS->getBaseTypeLoc()};
llvm_unreachable("Unexpected type in ObjectAccess");
}
@@ -738,12 +744,14 @@ class KernelParamsChecker : public ConstSubobjectVisitor<KernelParamsChecker> {
// Returns true if subobjects should be visited and false otherwise.
bool checkType(QualType Ty) {
- auto emitDiagnostic = [this](clang::diag::kind mesg) {
- const auto &[Type, Loc] =
- getObjectAccessDebugInfo(ObjectAccessPath.back());
- SemaSYCLRef.Diag(Loc, mesg) << Type;
+ auto emitDiagnostic = [this](clang::diag::kind DiagId, auto &&...Args) {
+ const auto &DiagDetail =
+ getObjectAccessDiagDetails(ObjectAccessPath.back());
+ (SemaSYCLRef.Diag(DiagDetail.Loc, DiagId)
+ << DiagDetail.Type << ... << Args);
emitObjectAccessPathNotes();
};
+
if (Ty->isReferenceType()) {
auto DirectParent = ObjectAccessPath.back();
// Reference cannot be a base, so just assume we came via a FieldDecl.
@@ -754,34 +762,34 @@ class KernelParamsChecker : public ConstSubobjectVisitor<KernelParamsChecker> {
return true;
}
- auto *DirectFieldParent = cast<const FieldDecl *>(DirectParent);
- SemaSYCLRef.Diag(DirectFieldParent->getLocation(),
- diag::err_bad_kernel_param_type)
- << DirectFieldParent->getType();
- emitObjectAccessPathNotes();
-
// Don't visit the type of the reference since any further invalid
// kernel parameter types contained within the referenced type
// might not be relevant once the programmer addresses the
// invalid use of a reference.
+ emitDiagnostic(diag::err_bad_kernel_param_type);
IsValid = false;
return false;
- } else if (Ty->isAtomicType()) {
+ }
+ if (Ty->isAtomicType()) {
emitDiagnostic(diag::err_bad_kernel_param_type);
IsValid = false;
return false;
- } else if (Ty->isStructureTypeWithFlexibleArrayMember()) {
- emitDiagnostic(diag::err_sycl_kernel_param_has_fam);
+ }
+ if (Ty->isStructureTypeWithFlexibleArrayMember()) {
+ emitDiagnostic(diag::err_sycl_kernel_bad_param_type,
+ diag::InvalidSYCLKernelParamReason::FAM);
IsValid = false;
return false;
- } else if (CXXRecordDecl *RD = Ty->getAsCXXRecordDecl()) {
+ }
+ // Disallow classes that inherit virtual base classes.
+ if (CXXRecordDecl *RD = Ty->getAsCXXRecordDecl()) {
if (RD->getNumVBases() > 0) {
- emitDiagnostic(diag::err_sycl_kernel_param_has_vbase);
+ emitDiagnostic(diag::err_sycl_kernel_bad_param_type,
+ diag::InvalidSYCLKernelParamReason::VirtualBases);
IsValid = false;
return false;
}
}
-
// Warn about pointer parameters in SYCL kernels if non-portable SYCL
// warnings are enabled.
if (Ty->isPointerType()) {
diff --git a/clang/test/SemaSYCL/sycl-kernel-param-restrictions.cpp b/clang/test/SemaSYCL/sycl-kernel-param-restrictions.cpp
index 452ce7660e017..01768bc79b52b 100644
--- a/clang/test/SemaSYCL/sycl-kernel-param-restrictions.cpp
+++ b/clang/test/SemaSYCL/sycl-kernel-param-restrictions.cpp
@@ -122,7 +122,7 @@ template <typename T> class Callable { // expected-note 2{{within field of type
T data; // expected-error 2{{'int &' cannot be used as the type of a kernel parameter}}
public:
Callable(T d) : data(d) {}
- void operator()() {
+ void operator()() const {
}
};
@@ -190,32 +190,34 @@ void test() {
} // namespace badref7
-#include <stdatomic.h>
// Check for atomic parameters and subobjects.
namespace atomic1 {
// Kernel entry point template definition.
template<typename KNT, typename T>
[[clang::sycl_kernel_entry_point(KNT)]]
-void kernel_single_task(T t) {} // expected-note-re {{within parameter 't' of type '(lambda at {{.*}})' declared here}}
- // expected-note-re at -1 {{within parameter 't' of type '(lambda at {{.*}})' declared here}}
- // expected-note-re at -2 {{within parameter 't' of type '(lambda at {{.*}})' declared here}}
- // expected-note-re at -3 {{within parameter 't' of type '(lambda at {{.*}})' declared here}}
- // expected-note at -4 {{within parameter 't' of type 'atomic1::Kernel' declared here}}
+void kernel_single_task(T t) {}
+// expected-note-re at -1 {{within parameter 't' of type '(lambda at {{.*}})' declared here}}
+// expected-note-re at -2 {{within parameter 't' of type '(lambda at {{.*}})' declared here}}
+// expected-note-re at -3 {{within parameter 't' of type '(lambda at {{.*}})' declared here}}
+// expected-note-re at -4 {{within parameter 't' of type '(lambda at {{.*}})' declared here}}
+// expected-note at -5 {{within parameter 't' of type 'atomic1::Kernel' declared here}}
struct Sa {
int a;
- _Atomic int b; // expected-error {{'_Atomic(int)' cannot be used as the type of a kernel parameter}}
- // expected-note at -3 {{within field of type 'Sa' declared here}}
- // expected-error at -2 {{'_Atomic(int)' cannot be used as the type of a kernel parameter}}
- // expected-note at -5 {{within field of type 'Sa' declared here}}
- // expected-error at -4 {{'_Atomic(int)' cannot be used as the type of a kernel parameter}}
- // expected-note at -7 {{within field of type 'Sa' declared here}}
+ _Atomic int b;
+ // expected-error at -1 {{'_Atomic(int)' cannot be used as the type of a kernel parameter}}
+ // expected-note at -4 {{within field of type 'Sa' declared here}}
+ // expected-error at -3 {{'_Atomic(int)' cannot be used as the type of a kernel parameter}}
+ // expected-note at -6 {{within field of type 'Sa' declared here}}
+ // expected-error at -5 {{'_Atomic(int)' cannot be used as the type of a kernel parameter}}
+ // expected-note at -8 {{within field of type 'Sa' declared here}}
};
class Kernel {
- Sa data{1, 2}; // expected-note at -1 {{within field of type 'Kernel' declared here}}
+ // expected-note at -1 {{within field of type 'Kernel' declared here}}
+ Sa data{1, 2};
public:
- void operator()() { }
+ void operator()() const { }
};
void test() {
@@ -248,17 +250,20 @@ namespace fam1 {
// Kernel entry point template definition.
template<typename KNT, typename T>
[[clang::sycl_kernel_entry_point(KNT)]]
-void kernel_single_task(T t) {} // expected-note {{within parameter 't' of type 'fam1::Kernel' declared here}}
+void kernel_single_task(T t) {}
+// expected-note at -1 {{within parameter 't' of type 'fam1::Kernel' declared here}}
struct FAM {
int a;
int b[];
};
-class Kernel { // expected-note {{within field of type 'Kernel' declared here}}
- FAM fam; // expected-error {{'FAM' contains a flexible array member and cannot be used as a SYCL kernel parameter}}
+class Kernel {
+// expected-note at -1 {{within field of type 'Kernel' declared here}}
+ FAM fam;
+ // expected-error at -1 {{'FAM' contains a flexible array member and cannot be used as the type of a SYCL kernel parameter}}
public:
- void operator()() { (void)fam; }
+ void operator()() const { (void)fam; }
};
void test() {
@@ -275,22 +280,25 @@ namespace nonportable1 {
// Kernel entry point template definition.
template<typename KNT, typename T>
[[clang::sycl_kernel_entry_point(KNT)]]
-void kernel_single_task(T t) {} // nonportable-note-re {{within parameter 't' of type '(lambda at {{.*}})' declared here}}
- // nonportable-note-re at -1 {{within parameter 't' of type '(lambda at {{.*}})' declared here}}
- // nonportable-note-re at -2 {{within parameter 't' of type '(lambda at {{.*}})' declared here}}
- // nonportable-note-re at -3 {{within parameter 't' of type '(lambda at {{.*}})' declared here}}
-
-struct S { // nonportable-note {{within field of type 'S' declared here}}
- // nonportable-note at -1 {{within field of type 'S' declared here}}
+void kernel_single_task(T t) {}
+// nonportable-note-re at -1 {{within parameter 't' of type '(lambda at {{.*}})' declared here}}
+// nonportable-note-re at -2 {{within parameter 't' of type '(lambda at {{.*}})' declared here}}
+// nonportable-note-re at -3 {{within parameter 't' of type '(lambda at {{.*}})' declared here}}
+// nonportable-note-re at -4 {{within parameter 't' of type '(lambda at {{.*}})' declared here}}
+
+struct S {
+// nonportable-note at -1 {{within field of type 'S' declared here}}
+// nonportable-note at -2 {{within field of type 'S' declared here}}
int *ptr;
- // nonportable-warning at -1 {{pointers used in SYCL kernels must point to device-accessible memory, i.e. the USM}}
- // nonportable-warning at -2 {{pointers used in SYCL kernels must point to device-accessible memory, i.e. the USM}}
+ // nonportable-warning at -1 {{pointers used in parameters to a SYCL kernel require a device that supports Unified Shared Memory (USM)}}
+ // nonportable-warning at -2 {{pointers used in parameters to a SYCL kernel require a device that supports Unified Shared Memory (USM)}}
};
-class C { // nonportable-note {{within field of type 'C' declared here}}
+class C {
+// nonportable-note at -1 {{within field of type 'C' declared here}}
private:
int *ptr;
- // nonportable-warning at -1 {{pointers used in SYCL kernels must point to device-accessible memory, i.e. the USM}}
+ // nonportable-warning at -1 {{pointers used in parameters to a SYCL kernel require a device that supports Unified Shared Memory (USM)}}
public:
C(int *p) : ptr(p) {}
};
@@ -298,7 +306,7 @@ class C { // nonportable-note {{within field of type 'C' declared here}}
void test() {
int *ptr;
kernel_single_task<class KN<25>>([=]{ (void)ptr; });
- // nonportable-warning at -1 {{pointers used in SYCL kernels must point to device-accessible memory, i.e. the USM}}
+ // nonportable-warning at -1 {{pointers used in parameters to a SYCL kernel require a device that supports Unified Shared Memory (USM)}}
// nonportable-note-re at -2 {{in instantiation of function template specialization 'nonportable1::kernel_single_task<KN<{{[0-9]+}}>, {{.*}}>' requested here}}
// nonportable-note at -3 {{within capture 'ptr' of lambda expression here}}
@@ -325,7 +333,9 @@ namespace vbase1 {
// Kernel entry point template definition.
template<typename KNT, typename T>
[[clang::sycl_kernel_entry_point(KNT)]]
-void kernel_single_task(T t) {} // expected-note-re {{within parameter 't' of type '(lambda at {{.*}})' declared here}}
+void kernel_single_task(T t) {}
+// expected-note-re at -1 {{within parameter 't' of type '(lambda at {{.*}})' declared here}}
+// expected-note-re at -2 {{within parameter 't' of type '(lambda at {{.*}})' declared here}}
class Base {
// No diagnostic is issued for data because recursive subobject visitation
@@ -338,15 +348,34 @@ class Base {
class Derived : virtual Base {
public:
Derived(int &a) : Base(a) {}
+};
+class A : public virtual Base {
+public:
+ A(int &a) : Base(a) {}
+};
+
+class B : public virtual Base {
+public:
+ B(int &a) : Base(a) {}
+};
+
+class Diamond : public A, public B {
+public:
+ Diamond(int &a) : Base(a), A(a), B(a) {}
};
void test() {
int p = 0;
Derived d{p};
kernel_single_task<class KN<29>>([=]{ (void)d; });
- // expected-error at -1 {{'Derived' inherits virtual base classes and cannot be used as a SYCL kernel parameter}}
+ // expected-error at -1 {{'Derived' inherits virtual base classes and cannot be used as the type of a SYCL kernel parameter}}
// expected-note-re at -2 {{in instantiation of function template specialization 'vbase1::kernel_single_task<KN<{{[0-9]+}}>, {{.*}}>' requested here}}
// expected-note at -3 {{within capture 'd' of lambda expression here}}
+ Diamond ab{p};
+ kernel_single_task<class KN<30>>([=]{ (void)ab; });
+ // expected-error at -1 {{'Diamond' inherits virtual base classes and cannot be used as the type of a SYCL kernel parameter}}
+ // expected-note-re at -2 {{in instantiation of function template specialization 'vbase1::kernel_single_task<KN<{{[0-9]+}}>, {{.*}}>' requested here}}
+ // expected-note at -3 {{within capture 'ab' of lambda expression here}}
}
} // namespace vbase1
>From f547989362f2e5ce3b4b1ca4d0a4c82a993c5c4d Mon Sep 17 00:00:00 2001
From: "Li, Ian" <ian.li at intel.com>
Date: Fri, 17 Jul 2026 09:13:34 -0700
Subject: [PATCH 11/11] Oh...
---
clang/lib/Sema/SemaSYCL.cpp | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp
index b8b26588e004f..b4145893b0b2d 100644
--- a/clang/lib/Sema/SemaSYCL.cpp
+++ b/clang/lib/Sema/SemaSYCL.cpp
@@ -747,8 +747,10 @@ class KernelParamsChecker : public ConstSubobjectVisitor<KernelParamsChecker> {
auto emitDiagnostic = [this](clang::diag::kind DiagId, auto &&...Args) {
const auto &DiagDetail =
getObjectAccessDiagDetails(ObjectAccessPath.back());
- (SemaSYCLRef.Diag(DiagDetail.Loc, DiagId)
- << DiagDetail.Type << ... << Args);
+ {
+ auto DB = SemaSYCLRef.Diag(DiagDetail.Loc, DiagId) << DiagDetail.Type;
+ (void)(DB << ... << Args);
+ }
emitObjectAccessPathNotes();
};
More information about the cfe-commits
mailing list