[clang] [clang][SYCL] Handle cdecl variadic functions for SYCL device (PR #194922)

Mariya Podchishchaeva via cfe-commits cfe-commits at lists.llvm.org
Thu Apr 30 08:06:05 PDT 2026


https://github.com/Fznamznon updated https://github.com/llvm/llvm-project/pull/194922

>From 078932df8964990c436307cb10af6614e8487690 Mon Sep 17 00:00:00 2001
From: "Podchishchaeva, Mariya" <mariya.podchishchaeva at intel.com>
Date: Wed, 29 Apr 2026 09:50:26 -0700
Subject: [PATCH 1/2] [clang][SYCL] Handle cdecl variadic functions for SYCL
 device

SYCL doesn't allow variadic functions to be called from device code.
Since SYCL device compilation mostly uses targets that don't natively
support variadic fucntions, we now issue an error even if the variadic
function is never called from the device if it has cdecl calling
convention attribute. We also now don't issue an error if a variadic
function is called from the device code. This patch defers the error
caused by cdecl attribute to the actual call point and adds diagnosing
of variadic function calls on device side using deferred diagnostics.
---
 .../clang/Basic/DiagnosticSemaKinds.td        |  2 +-
 clang/lib/Sema/SemaChecking.cpp               |  6 +++
 clang/lib/Sema/SemaDeclAttr.cpp               | 14 +++---
 clang/test/SemaSYCL/sycl-cconv.cpp            | 35 +++++++++++++++
 clang/test/SemaSYCL/variadic-func-call.cpp    | 45 +++++++++++++++++++
 5 files changed, 93 insertions(+), 9 deletions(-)
 create mode 100644 clang/test/SemaSYCL/sycl-cconv.cpp
 create mode 100644 clang/test/SemaSYCL/variadic-func-call.cpp

diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 1302c4296885b..4cee21108ad4f 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -9752,7 +9752,7 @@ def warn_kern_is_inline : Warning<
   "ignored 'inline' attribute on kernel function %0">,
   InGroup<CudaCompat>;
 def err_variadic_device_fn : Error<
-  "CUDA device code does not support variadic functions">;
+  "%select{CUDA|SYCL}0 device code does not support variadic functions">;
 def err_va_arg_in_device : Error<
 "CUDA device code does not support va_arg">;
 def err_alias_not_supported_on_nvptx : Error<"CUDA older than 10.0 does not support .alias">;
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 7caae4e66f5b7..9741b9cc41e8a 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -76,6 +76,7 @@
 #include "clang/Sema/SemaPPC.h"
 #include "clang/Sema/SemaRISCV.h"
 #include "clang/Sema/SemaSPIRV.h"
+#include "clang/Sema/SemaSYCL.h"
 #include "clang/Sema/SemaSystemZ.h"
 #include "clang/Sema/SemaWasm.h"
 #include "clang/Sema/SemaX86.h"
@@ -4459,6 +4460,11 @@ void Sema::checkCall(NamedDecl *FDecl, const FunctionProtoType *Proto,
     }
   }
 
+  if (FD && FD->isVariadic() && getLangOpts().SYCLIsDevice &&
+      !isUnevaluatedContext()) {
+    SYCL().DiagIfDeviceCode(Loc, diag::err_variadic_device_fn) << /*SYCL=*/1;
+  }
+
   if (FD)
     diagnoseArgDependentDiagnoseIfAttrs(FD, ThisArg, Args, Loc);
 }
diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index 76073ed80175f..28e51848609bb 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -5823,14 +5823,12 @@ bool Sema::CheckCallingConvAttr(const ParsedAttr &Attrs, CallingConv &CC,
       A = HostTI->checkCallingConvention(CC);
     if (A == TargetInfo::CCCR_OK && CheckDevice && DeviceTI)
       A = DeviceTI->checkCallingConvention(CC);
-  } else if (LangOpts.SYCLIsDevice && TI.getTriple().isAMDGPU() &&
-             CC == CC_X86VectorCall) {
-    // Assuming SYCL Device AMDGPU CC_X86VectorCall functions are always to be
-    // emitted on the host. The MSVC STL has CC-based specializations so we
-    // cannot change the CC to be the default as that will cause a clash with
-    // another specialization.
-    A = TI.checkCallingConvention(CC);
-    if (Aux && A != TargetInfo::CCCR_OK)
+  } else if (LangOpts.SYCLIsDevice) {
+    // In SYCL we may meet unsupported calling conventions in host code,
+    // especially inside of included headers. Now we don't know if they will be
+    // emitted, so we just defer any diagnostics. Check for the host triple if
+    // we have one, since everything is still emitted for the host.
+    if (Aux)
       A = Aux->checkCallingConvention(CC);
   } else {
     A = TI.checkCallingConvention(CC);
diff --git a/clang/test/SemaSYCL/sycl-cconv.cpp b/clang/test/SemaSYCL/sycl-cconv.cpp
new file mode 100644
index 0000000000000..b4b5e35ed0614
--- /dev/null
+++ b/clang/test/SemaSYCL/sycl-cconv.cpp
@@ -0,0 +1,35 @@
+// RUN: %clang_cc1 -isystem %S/Inputs/ -fsycl-is-device -triple spirv64 -aux-triple x86_64-pc-windows-msvc -fsyntax-only -verify %s
+// RUN: %clang_cc1 -isystem %S/Inputs/ -fsycl-is-device -triple spirv64 -fsyntax-only -verify %s
+
+// Check that there is no error/warning emitted for cdecl functions compiled for
+// SYCL device. Make sure variadic calls from within device code are diagnosed.
+
+__inline __cdecl int printf(char const* const _Format, ...) { return 0; }
+
+// FIXME: that should be diagnosed.
+[[clang::sycl_external]] int foo(int, ...) { return 0; }
+
+__inline __cdecl int moo() { return 0; }
+
+void bar() {
+  printf("hello\n");
+}
+
+template<typename KN, typename...Args>
+void sycl_kernel_launch(Args ...args) {}
+
+template<typename KN, typename K>
+[[clang::sycl_kernel_entry_point(KN)]]
+__cdecl void sycl_entry_point(K k) {
+  k(); // expected-note {{called by}}
+}
+
+int main() {
+  //expected-error at +1 {{SYCL device code does not support variadic functions}}
+  sycl_entry_point<class kn>([]() { printf("world\n");
+     moo();
+  //expected-error at +1 {{SYCL device code does not support variadic functions}}
+     foo(1,2); });
+  bar();
+  return 0;
+}
diff --git a/clang/test/SemaSYCL/variadic-func-call.cpp b/clang/test/SemaSYCL/variadic-func-call.cpp
new file mode 100644
index 0000000000000..a9ce19dad226d
--- /dev/null
+++ b/clang/test/SemaSYCL/variadic-func-call.cpp
@@ -0,0 +1,45 @@
+// RUN: %clang_cc1 -isystem %S/Inputs/ -fsycl-is-device -triple spirv64 -aux-triple x86_64-pc-windows-msvc -fsyntax-only -verify %s
+// RUN: %clang_cc1 -isystem %S/Inputs/ -fsycl-is-device -triple spirv64 -fsyntax-only -verify %s
+
+template<typename KN, typename...Args>
+void sycl_kernel_launch(Args ...args) {}
+
+template<typename KN, typename K>
+[[clang::sycl_kernel_entry_point(KN)]]
+void sycl_entry_point(K k) {
+  k(); // expected-note 2{{called by}}
+}
+
+void variadic(int, ...) {}
+namespace NS {
+void variadic(int, ...) {}
+}
+
+struct S {
+  S(int, ...) {}
+  void operator()(int, ...) {}
+};
+
+void foo() {
+  auto x = [](int, ...) {};
+  x(5, 10); //expected-error{{SYCL device code does not support variadic functions}}
+}
+
+void overloaded(int, int) {}
+void overloaded(int, ...) {}
+
+int main() {
+  sycl_entry_point<class FK>([]() {
+    variadic(5);        //expected-error{{SYCL device code does not support variadic functions}}
+    variadic(5, 2);     //expected-error{{SYCL device code does not support variadic functions}}
+    NS::variadic(5, 3); //expected-error{{SYCL device code does not support variadic functions}}
+    S s(5, 4);          //expected-error{{SYCL device code does not support variadic functions}}
+    S s2(5);            //expected-error{{SYCL device code does not support variadic functions}}
+    s(5, 5);            //expected-error{{SYCL device code does not support variadic functions}}
+    s2(5);              //expected-error{{SYCL device code does not support variadic functions}}
+    foo();              //expected-note{{called by 'operator()'}}
+    overloaded(5, 6);   //expected-no-error
+    overloaded(5, s);   //expected-error{{SYCL device code does not support variadic functions}}
+    overloaded(5);      //expected-error{{SYCL device code does not support variadic functions}}
+  });
+}

>From bc03757193a14086847397f8bbeb5962d9554bd1 Mon Sep 17 00:00:00 2001
From: "Podchishchaeva, Mariya" <mariya.podchishchaeva at intel.com>
Date: Thu, 30 Apr 2026 08:05:32 -0700
Subject: [PATCH 2/2] Incorporate feedback

---
 clang/include/clang/Basic/DiagnosticSemaKinds.td | 3 ++-
 clang/lib/Sema/SemaChecking.cpp                  | 6 +++---
 2 files changed, 5 insertions(+), 4 deletions(-)

diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 4cee21108ad4f..8c4c6f6bce8d7 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -9752,7 +9752,8 @@ def warn_kern_is_inline : Warning<
   "ignored 'inline' attribute on kernel function %0">,
   InGroup<CudaCompat>;
 def err_variadic_device_fn : Error<
-  "%select{CUDA|SYCL}0 device code does not support variadic functions">;
+  "%enum_select<OffloadLang>{%CUDA{CUDA}|%SYCL{SYCL}}0 device code does not "
+  "support variadic functions">;
 def err_va_arg_in_device : Error<
 "CUDA device code does not support va_arg">;
 def err_alias_not_supported_on_nvptx : Error<"CUDA older than 10.0 does not support .alias">;
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index ac730a4b67cee..9f950f185f8f0 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -4468,9 +4468,9 @@ void Sema::checkCall(NamedDecl *FDecl, const FunctionProtoType *Proto,
   }
 
   if (FD && FD->isVariadic() && getLangOpts().SYCLIsDevice &&
-      !isUnevaluatedContext()) {
-    SYCL().DiagIfDeviceCode(Loc, diag::err_variadic_device_fn) << /*SYCL=*/1;
-  }
+      !isUnevaluatedContext())
+    SYCL().DiagIfDeviceCode(Loc, diag::err_variadic_device_fn)
+        << diag::OffloadLang::SYCL;
 
   if (FD)
     diagnoseArgDependentDiagnoseIfAttrs(FD, ThisArg, Args, Loc);



More information about the cfe-commits mailing list