Author: schittir
Date: 2026-11-03T11:56:28-05:00
New Revision: 352d9bcc7b6689e5993c30df5658dadb60442a7a

URL: 
https://github.com/llvm/llvm-project/commit/352d9bcc7b6689e5993c30df5658dadb60442a7a
DIFF: 
https://github.com/llvm/llvm-project/commit/352d9bcc7b6689e5993c30df5658dadb60442a7a.diff

LOG: [clang][SYCL] Diagnose variadic sycl_external function (#216393)

SYCL device code does not support variadic function calls.

Added: 
    clang/test/CodeGenSYCL/sycl-external-attr-variadic.cpp
    clang/test/SemaSYCL/sycl-external-attr-variadic-undefined.cpp

Modified: 
    clang/include/clang/Basic/AttrDocs.td
    clang/include/clang/Basic/DiagnosticSemaKinds.td
    clang/include/clang/Sema/SemaSYCL.h
    clang/lib/Sema/SemaDeclAttr.cpp
    clang/lib/Sema/SemaSYCL.cpp
    clang/test/CodeGenSPIRV/spirv-host-adaptation-valist.cpp
    clang/test/SemaSYCL/sycl-cconv.cpp
    clang/test/SemaSYCL/sycl-external-attr.cpp
    clang/test/SemaSYCL/variadic-func-call.cpp

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/Basic/AttrDocs.td 
b/clang/include/clang/Basic/AttrDocs.td
index 687e022c7bd61f..2300c8456ef164 100644
--- a/clang/include/clang/Basic/AttrDocs.td
+++ b/clang/include/clang/Basic/AttrDocs.td
@@ -624,6 +624,10 @@ following requirements:
 The attribute shall be present on the first declaration of a function and
 may optionally be present on subsequent declarations.
 
+SYCL prohibits calls to a variadic function in device functions. Since there is
+little reason to emit a function that cannot be called, the attribute is 
ignored,
+with a warning, when applied to a variadic function.
+
 When compiling for a SYCL device target that does not support the generic
 address space, the function shall not specify a raw pointer or reference type
 as the return type or as a parameter type.
@@ -638,6 +642,8 @@ The following examples demonstrate the use of this 
attribute:
 [[clang::sycl_external]] extern void Baz(); // Ok.
 
 [[clang::sycl_external]] static void Quux() { /* ... */ } // error:  Quux() 
has internal linkage.
+
+[[clang::sycl_external]] void Corge(int, ...); // warning: attribute ignored;  
Corge() is variadic.
 ```
 
   }];

diff  --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 671bdd63af6861..a2fc0206c445be 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -13624,6 +13624,10 @@ def err_sycl_external_invalid_main : Error<
   "%0 cannot be applied to the 'main' function">;
 def err_sycl_external_invalid_deleted_function : Error<
   "%0 cannot be applied to an explicitly deleted function">;
+def warn_sycl_external_ignored_variadic_function : Warning<
+  "%0 attribute ignored; a variadic function cannot be called from device "
+  "code">,
+  InGroup<IgnoredAttributes>;
 def warn_sycl_external_missing_on_first_decl : Warning<
   "%0 attribute does not appear on the first declaration">,
   InGroup<NonPortableSYCL>;

diff  --git a/clang/include/clang/Sema/SemaSYCL.h 
b/clang/include/clang/Sema/SemaSYCL.h
index 4980aa44c30129..f4e4a5ef3e4adf 100644
--- a/clang/include/clang/Sema/SemaSYCL.h
+++ b/clang/include/clang/Sema/SemaSYCL.h
@@ -61,6 +61,7 @@ class SemaSYCL : public SemaBase {
                                        SourceLocation RParen,
                                        ParsedType ParsedTy);
 
+  void handleSYCLExternalAttr(Decl *D, const ParsedAttr &AL);
   void handleKernelAttr(Decl *D, const ParsedAttr &AL);
   void handleKernelEntryPointAttr(Decl *D, const ParsedAttr &AL);
 

diff  --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index 33b680c4d93d4c..e57f1de9c11007 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -7901,7 +7901,7 @@ ProcessDeclAttribute(Sema &S, Decl *D, const ParsedAttr 
&AL,
     S.SYCL().handleKernelAttr(D, AL);
     break;
   case ParsedAttr::AT_SYCLExternal:
-    handleSimpleAttribute<SYCLExternalAttr>(S, D, AL);
+    S.SYCL().handleSYCLExternalAttr(D, AL);
     break;
   case ParsedAttr::AT_SYCLKernelEntryPoint:
     S.SYCL().handleKernelEntryPointAttr(D, AL);

diff  --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp
index e180b3655bd730..56675ee9f2d107 100644
--- a/clang/lib/Sema/SemaSYCL.cpp
+++ b/clang/lib/Sema/SemaSYCL.cpp
@@ -278,6 +278,18 @@ static bool CheckSYCLKernelName(Sema &S, SourceLocation 
Loc,
   return false;
 }
 
+void SemaSYCL::handleSYCLExternalAttr(Decl *D, const ParsedAttr &AL) {
+  // SYCL 2020 section 5.4 prohibits calling a variadic function from device
+  // code, so the attribute cannot be honored; declaring one is not prohibited,
+  // so ignore the attribute rather than reject the declaration.
+  if (cast<FunctionDecl>(D)->isVariadic()) {
+    Diag(AL.getLoc(), diag::warn_sycl_external_ignored_variadic_function) << 
AL;
+    return;
+  }
+
+  handleSimpleAttribute<SYCLExternalAttr>(*this, D, AL);
+}
+
 void SemaSYCL::CheckSYCLExternalFunctionDecl(FunctionDecl *FD) {
   const auto *SEAttr = FD->getAttr<SYCLExternalAttr>();
   assert(SEAttr && "Missing sycl_external attribute");

diff  --git a/clang/test/CodeGenSPIRV/spirv-host-adaptation-valist.cpp 
b/clang/test/CodeGenSPIRV/spirv-host-adaptation-valist.cpp
index d926e30376b188..814671329423e3 100644
--- a/clang/test/CodeGenSPIRV/spirv-host-adaptation-valist.cpp
+++ b/clang/test/CodeGenSPIRV/spirv-host-adaptation-valist.cpp
@@ -5,7 +5,10 @@
 // RUN: %clang_cc1 -triple spirv64-unknown-unknown -aux-triple 
x86_64-pc-windows-msvc \
 // RUN:   -fsycl-is-device -emit-llvm -o - %s | FileCheck 
--check-prefix=WINDOWS %s
 
-[[clang::sycl_external]] int f(int n, ...) {
+// SYCL 2020 section 5.4, "Language restrictions for device functions", 
prohibits
+// calls to variadic functions in device code, but doesn't prohibit other 
ODR-uses.
+// Function f() is emitted during device compilation due to the ODR-use in g().
+int f(int n, ...) {
   __builtin_va_list ap1, ap2;
   __builtin_va_start(ap1, n);
   int v = __builtin_va_arg(ap1, int);
@@ -15,6 +18,9 @@
   return v;
 }
 
+using FP = int (*)(int, ...);
+[[clang::sycl_external]] FP g() { return f; }
+
 // LINUX:    define {{.*}} i32 @_Z1fiz(i32 noundef %n, ...) {{.*}} {
 // LINUX:      %ap1 = alloca [1 x %struct.__va_list_tag], align 8
 // LINUX:      %ap2 = alloca [1 x %struct.__va_list_tag], align 8

diff  --git a/clang/test/CodeGenSYCL/sycl-external-attr-variadic.cpp 
b/clang/test/CodeGenSYCL/sycl-external-attr-variadic.cpp
new file mode 100644
index 00000000000000..e45af97492447e
--- /dev/null
+++ b/clang/test/CodeGenSYCL/sycl-external-attr-variadic.cpp
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 -fsycl-is-device -triple spir64-unknown-unknown \
+// RUN:   -disable-llvm-passes -emit-llvm -verify %s -o - | FileCheck %s \
+// RUN:   --implicit-check-not=variadic_fn_test1 \
+// RUN:   --implicit-check-not=reached_from_variadic_fn_test2 \
+// RUN:   --implicit-check-not=variadic_caller_fn_test3
+
+// This test checks that the sycl_external attribute is ignored for variadic
+// functions; no device code is emitted for such functions.
+
+// expected-warning@+1{{'clang::sycl_external' attribute ignored; a variadic 
function cannot be called from device code}}
+[[clang::sycl_external]] int variadic_fn_test1(int n, ...) { return n; }
+
+int reached_from_variadic_fn_test2() { return 1; }
+
+// expected-warning@+1{{'clang::sycl_external' attribute ignored; a variadic 
function cannot be called from device code}}
+[[clang::sycl_external]] int variadic_caller_fn_test3(int n, ...) {
+  return reached_from_variadic_fn_test2();
+}
+
+// Check that non-variadic functions are emitted to ensure the lack of emission
+// for the others is due to their being variadic functions.
+[[clang::sycl_external]] int non_variadic_fn_test4(int n) { return n; }
+// CHECK: define dso_local spir_func noundef i32 @{{.*}}non_variadic_fn_test4

diff  --git a/clang/test/SemaSYCL/sycl-cconv.cpp 
b/clang/test/SemaSYCL/sycl-cconv.cpp
index 1b250676cf4784..c60501d5bd0bed 100644
--- a/clang/test/SemaSYCL/sycl-cconv.cpp
+++ b/clang/test/SemaSYCL/sycl-cconv.cpp
@@ -6,7 +6,7 @@
 
 __inline __cdecl int printf(char const* const _Format, ...) { return 0; }
 
-// FIXME: that should be diagnosed.
+// expected-warning@+1 {{'clang::sycl_external' attribute ignored; a variadic 
function cannot be called from device code}}
 [[clang::sycl_external]] int foo(int, ...) { return 0; }
 
 __inline __cdecl int moo() { return 0; }

diff  --git a/clang/test/SemaSYCL/sycl-external-attr-variadic-undefined.cpp 
b/clang/test/SemaSYCL/sycl-external-attr-variadic-undefined.cpp
new file mode 100644
index 00000000000000..8039017ae2b7ec
--- /dev/null
+++ b/clang/test/SemaSYCL/sycl-external-attr-variadic-undefined.cpp
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -fsycl-is-device -triple spir64-unknown-unknown 
-fsyntax-only \
+// RUN:   -verify %s
+
+// This test checks the diagnostics issued for an ODR-use of a variadic 
function
+// declared, but not defined, with the ignored sycl_external attribute.
+
+// expected-warning@+1{{'clang::sycl_external' attribute ignored; a variadic 
function cannot be called from device code}}
+[[clang::sycl_external]] void undefined_variadic_fn_test1(int, ...);
+
+[[clang::sycl_external]] void use_undefined_variadic_fn_test2() {
+  // FIXME: Clang does not diagnose an ODR-use of a function that is neither
+  // defined in this translation unit nor declared sycl_external.
+  // expected error once it does.
+  (void)&undefined_variadic_fn_test1;
+}

diff  --git a/clang/test/SemaSYCL/sycl-external-attr.cpp 
b/clang/test/SemaSYCL/sycl-external-attr.cpp
index ebda94e7d50307..922ca9c328846e 100644
--- a/clang/test/SemaSYCL/sycl-external-attr.cpp
+++ b/clang/test/SemaSYCL/sycl-external-attr.cpp
@@ -113,6 +113,36 @@ class D {
 // expected-error@+1{{'clang::sycl_external' cannot be applied to an 
explicitly deleted function}}
 [[clang::sycl_external]] void del() = delete;
 
+// SYCL device code does not support variadic functions.
+// expected-warning@+1{{'clang::sycl_external' attribute ignored; a variadic 
function cannot be called from device code}}
+[[clang::sycl_external]] void var(int, ...) {}
+
+// expected-warning@+1{{'clang::sycl_external' attribute ignored; a variadic 
function cannot be called from device code}}
+[[clang::sycl_external]] void vardecl(int, ...);
+
+// expected-warning@+1{{'clang::sycl_external' attribute ignored; a variadic 
function cannot be called from device code}}
+[[clang::sycl_external]] void varredecl(int, ...);
+// expected-warning@+1{{'clang::sycl_external' attribute ignored; a variadic 
function cannot be called from device code}}
+[[clang::sycl_external]] void varredecl(int, ...) {}
+
+// expected-warning@+2{{'clang::sycl_external' attribute ignored; a variadic 
function cannot be called from device code}}
+class E {
+  [[clang::sycl_external]] void mvar(int, ...) {}
+};
+
+template<typename... Ts>
+[[clang::sycl_external]] void pack(Ts...) {}
+template void pack(int);
+
+// expected-warning@+2{{'clang::sycl_external' attribute ignored; a variadic 
function cannot be called from device code}}
+template<typename T>
+[[clang::sycl_external]] void tvar(T, ...) {}
+template void tvar(int, ...);
+using TVarFP = void (*)(char, ...);
+[[clang::sycl_external]] TVarFP tvar_implicit_instantiation() {
+  return &tvar<char>;
+}
+
 struct NonCopyable {
   ~NonCopyable() = delete;
   [[clang::sycl_external]] NonCopyable(const NonCopyable&) = default;

diff  --git a/clang/test/SemaSYCL/variadic-func-call.cpp 
b/clang/test/SemaSYCL/variadic-func-call.cpp
index a9ce19dad226d3..a8e5143a7880d8 100644
--- a/clang/test/SemaSYCL/variadic-func-call.cpp
+++ b/clang/test/SemaSYCL/variadic-func-call.cpp
@@ -15,6 +15,9 @@ namespace NS {
 void variadic(int, ...) {}
 }
 
+// expected-warning@+1{{'clang::sycl_external' attribute ignored; a variadic 
function cannot be called from device code}}
+[[clang::sycl_external]] void external_variadic(int, ...) {}
+
 struct S {
   S(int, ...) {}
   void operator()(int, ...) {}
@@ -33,6 +36,7 @@ int main() {
     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}}
+    external_variadic(5, 4); //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}}


        
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to