[clang] [SYCL] SYCL host kernel launch support for the sycl_kernel_entry_point attribute. (PR #152403)

Tom Honermann via cfe-commits cfe-commits at lists.llvm.org
Wed Mar 4 15:10:00 PST 2026


https://github.com/tahonermann updated https://github.com/llvm/llvm-project/pull/152403

>From ae0d89e108d0ae39ddbe211756e933f36eff94e3 Mon Sep 17 00:00:00 2001
From: Tom Honermann <tom.honermann at intel.com>
Date: Wed, 6 Aug 2025 19:26:54 -0700
Subject: [PATCH 01/29] [SYCL] SYCL host kernel launch support for the
 sycl_kernel_entry_point attribute.

The `sycl_kernel_entry_point` attribute facilitates the generation of an
offload kernel entry point function with parameters corresponding to the
(potentially decomposed) kernel arguments and a body that (potentially
reconstructs the arguments and) executes the kernel. This change adds
symmetric support for the SYCL host through an interface that provides
symbol names and (potentially decomposed) kernel arguments to the SYCL
library.

Consider the following function declared with the `sycl_kernel_entry_point`
attribute with a call to this function occurring in the implementation of
a SYCL kernel invocation function such as `sycl::handler::single_task()`.
  template<typename KernelNameType, typename KernelType>
  [[clang::sycl_kernel_entry_point(KernelNameType)]]
  void kernel_entry_point(KernelType kerne) {
    kernel();
  }

The body of the above function specifies the parameters and body of the
generated offload kernel entry point. Clearly, a call to the above function
by a SYCL kernel invocation function is not intended to execute the body
as written. Previously, code generation emitted an empty function body so
that calls to the function had no effect other than to trigger the generation
of the offload kernel entry point. The function body is therefore available
to hook for SYCL library support and is now substituted with a call to a
(SYCL library provided) function template named `sycl_enqueue_kernel_launch()`
with the kernel name type passed as the first template argument, the
symbol name of the offload kernel entry point passed as a string literal for
the first function argument, and the (possibly decomposed) parameters passed
as the remaining explicit function arguments. Given a call like this:
  kernel_entry_point<struct KN>([]{})
the body of the instantiated `kernel_entry_point()` specialization would be
substituted as follows with "kernel-symbol-name" substituted for the
generated symbol name and `kernel` forwarded (This assumes no kernel
argument decomposition; if decomposition was required, `kernel` would be
replaced with its corresponding decomposed arguments).
  sycl_enqueue_kernel_launch<KN>("kernel-symbol-name", kernel)

Name lookup and overload resolution for the `sycl_enqueue_kernel_launch()`
function is performed at the point of definition of the
`sycl_kernel_entry_point` attributed function (or the point of instantiation
for an instantiated function template specialization). If overload
resolution fails, the program is ill-formed.

Implementation of the `sycl_enqueue_kernel_launch()` function might require
additional information provided by the SYCL library. This is facilitated by
removing the previous prohibition against use of the `sycl_kernel_entry_point`
attribute with a non-static member function. If the `sycl_kernel_entry_point`
attributed function is a non-static member function, then overload resolution
for the `sycl_enqueue_kernel_launch()` function template may select a
non-static member function in which case, `this` will be implicitly passed
as the implicit object argument.

If a `sycl_kernel_entry_point` attributed function is a non-static member
function, use of `this` in a potentially evaluated expression is prohibited
in the definition (since `this` is not a kernel argument and will not be
available within the generated offload kernel entry point function).

Support for kernel argument decomposition and reconstruction is not yet
implemented.
---
 clang/include/clang/AST/ASTNodeTraverser.h    |   4 +-
 clang/include/clang/AST/RecursiveASTVisitor.h |   1 +
 clang/include/clang/AST/StmtSYCL.h            |  28 ++--
 clang/include/clang/Basic/AttrDocs.td         | 151 +++++++++++-------
 .../clang/Basic/DiagnosticSemaKinds.td        |   5 +-
 clang/lib/AST/ASTContext.cpp                  |   4 +
 clang/lib/AST/StmtPrinter.cpp                 |   2 +-
 clang/lib/CodeGen/CGStmt.cpp                  |  17 +-
 clang/lib/CodeGen/CodeGenFunction.h           |   2 +
 clang/lib/CodeGen/CodeGenSYCL.cpp             |  15 ++
 clang/lib/Sema/SemaExceptionSpec.cpp          |  11 +-
 clang/lib/Sema/SemaSYCL.cpp                   | 139 +++++++++++++---
 clang/lib/Serialization/ASTReaderStmt.cpp     |   1 +
 clang/lib/Serialization/ASTWriterStmt.cpp     |   1 +
 clang/test/AST/ast-print-sycl-kernel-call.cpp |  22 +++
 .../ast-dump-sycl-kernel-call-stmt.cpp        |  51 +++++-
 .../CodeGenSYCL/kernel-caller-entry-point.cpp |  13 +-
 ...-kernel-entry-point-attr-appertainment.cpp |  29 ++--
 .../sycl-kernel-entry-point-attr-grammar.cpp  |   2 +
 ...cl-kernel-entry-point-attr-kernel-name.cpp |   2 +
 .../sycl-kernel-entry-point-attr-sfinae.cpp   |   2 +
 21 files changed, 374 insertions(+), 128 deletions(-)
 create mode 100644 clang/test/AST/ast-print-sycl-kernel-call.cpp

diff --git a/clang/include/clang/AST/ASTNodeTraverser.h b/clang/include/clang/AST/ASTNodeTraverser.h
index e74bb72571d64..0c64fb7d75df3 100644
--- a/clang/include/clang/AST/ASTNodeTraverser.h
+++ b/clang/include/clang/AST/ASTNodeTraverser.h
@@ -836,8 +836,10 @@ class ASTNodeTraverser
 
   void VisitSYCLKernelCallStmt(const SYCLKernelCallStmt *Node) {
     Visit(Node->getOriginalStmt());
-    if (Traversal != TK_IgnoreUnlessSpelledInSource)
+    if (Traversal != TK_IgnoreUnlessSpelledInSource) {
+      Visit(Node->getKernelLaunchStmt());
       Visit(Node->getOutlinedFunctionDecl());
+    }
   }
 
   void VisitOMPExecutableDirective(const OMPExecutableDirective *Node) {
diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h
index cfee62a362b1e..4ed15ea52e21a 100644
--- a/clang/include/clang/AST/RecursiveASTVisitor.h
+++ b/clang/include/clang/AST/RecursiveASTVisitor.h
@@ -3032,6 +3032,7 @@ DEF_TRAVERSE_STMT(CapturedStmt, { TRY_TO(TraverseDecl(S->getCapturedDecl())); })
 DEF_TRAVERSE_STMT(SYCLKernelCallStmt, {
   if (getDerived().shouldVisitImplicitCode()) {
     TRY_TO(TraverseStmt(S->getOriginalStmt()));
+    TRY_TO(TraverseStmt(S->getKernelLaunchStmt()));
     TRY_TO(TraverseDecl(S->getOutlinedFunctionDecl()));
     ShouldVisitChildren = false;
   }
diff --git a/clang/include/clang/AST/StmtSYCL.h b/clang/include/clang/AST/StmtSYCL.h
index 28ace12d7916b..70d8137992110 100644
--- a/clang/include/clang/AST/StmtSYCL.h
+++ b/clang/include/clang/AST/StmtSYCL.h
@@ -28,35 +28,45 @@ namespace clang {
 /// of such a function specifies the statements to be executed on a SYCL device
 /// to invoke a SYCL kernel with a particular set of kernel arguments. The
 /// SYCLKernelCallStmt associates an original statement (the compound statement
-/// that is the function body) with an OutlinedFunctionDecl that holds the
-/// kernel parameters and the transformed body. During code generation, the
-/// OutlinedFunctionDecl is used to emit an offload kernel entry point suitable
-/// for invocation from a SYCL library implementation. If executed, the
-/// SYCLKernelCallStmt behaves as a no-op; no code generation is performed for
-/// it.
+/// that is the function body) with a kernel launch statement to execute on a
+/// SYCL host and an OutlinedFunctionDecl that holds the kernel parameters and
+/// the transformed body to execute on a SYCL device. During code generation,
+/// the OutlinedFunctionDecl is used to emit an offload kernel entry point
+/// suitable for invocation from a SYCL library implementation.
 class SYCLKernelCallStmt : public Stmt {
   friend class ASTStmtReader;
   friend class ASTStmtWriter;
 
 private:
   Stmt *OriginalStmt = nullptr;
+  Stmt *KernelLaunchStmt = nullptr;
   OutlinedFunctionDecl *OFDecl = nullptr;
 
 public:
   /// Construct a SYCL kernel call statement.
-  SYCLKernelCallStmt(CompoundStmt *CS, OutlinedFunctionDecl *OFD)
-      : Stmt(SYCLKernelCallStmtClass), OriginalStmt(CS), OFDecl(OFD) {}
+  SYCLKernelCallStmt(CompoundStmt *CS, Stmt *S, OutlinedFunctionDecl *OFD)
+      : Stmt(SYCLKernelCallStmtClass), OriginalStmt(CS), KernelLaunchStmt(S),
+        OFDecl(OFD) {}
 
   /// Construct an empty SYCL kernel call statement.
   SYCLKernelCallStmt(EmptyShell Empty) : Stmt(SYCLKernelCallStmtClass, Empty) {}
 
-  /// Retrieve the model statement.
+  /// Retrieve the original statement.
   CompoundStmt *getOriginalStmt() { return cast<CompoundStmt>(OriginalStmt); }
   const CompoundStmt *getOriginalStmt() const {
     return cast<CompoundStmt>(OriginalStmt);
   }
+
+  /// Set the original statement.
   void setOriginalStmt(CompoundStmt *CS) { OriginalStmt = CS; }
 
+  /// Retrieve the kernel launch statement.
+  Stmt *getKernelLaunchStmt() { return KernelLaunchStmt; }
+  const Stmt *getKernelLaunchStmt() const { return KernelLaunchStmt; }
+
+  /// Set the kernel launch statement.
+  void setKernelLaunchStmt(Stmt *S) { KernelLaunchStmt = S; }
+
   /// Retrieve the outlined function declaration.
   OutlinedFunctionDecl *getOutlinedFunctionDecl() { return OFDecl; }
   const OutlinedFunctionDecl *getOutlinedFunctionDecl() const { return OFDecl; }
diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td
index cad45501df6d2..e3948df7e3598 100644
--- a/clang/include/clang/Basic/AttrDocs.td
+++ b/clang/include/clang/Basic/AttrDocs.td
@@ -532,13 +532,13 @@ The following examples demonstrate the use of this attribute:
 def SYCLKernelEntryPointDocs : Documentation {
   let Category = DocCatFunction;
   let Content = [{
-The ``sycl_kernel_entry_point`` attribute facilitates the generation of an
-offload kernel entry point, sometimes called a SYCL kernel caller function,
-suitable for invoking a SYCL kernel on an offload device. The attribute is
-intended for use in the implementation of SYCL kernel invocation functions
-like the ``single_task`` and ``parallel_for`` member functions of the
-``sycl::handler`` class specified in section 4.9.4, "Command group ``handler``
-class", of the SYCL 2020 specification.
+The ``sycl_kernel_entry_point`` attribute facilitates the launch of a SYCL
+kernel and the generation of an offload kernel entry point, sometimes called
+a SYCL kernel caller function, suitable for invoking a SYCL kernel on an
+offload device. The attribute is intended for use in the implementation of
+SYCL kernel invocation functions like the ``single_task`` and ``parallel_for``
+member functions of the ``sycl::handler`` class specified in section 4.9.4,
+"Command group ``handler`` class", of the SYCL 2020 specification.
 
 The attribute requires a single type argument that specifies a class type that
 meets the requirements for a SYCL kernel name as described in section 5.2,
@@ -550,7 +550,7 @@ The attribute only appertains to functions and only those that meet the
 following requirements.
 
 * Has a non-deduced ``void`` return type.
-* Is not a non-static member function, constructor, or destructor.
+* Is not a constructor or destructor.
 * Is not a C variadic function.
 * Is not a coroutine.
 * Is not defined as deleted or as defaulted.
@@ -565,39 +565,43 @@ follows.
 
   namespace sycl {
   class handler {
+    template<typename KernelNameType, typename... Ts>
+    void sycl_enqueue_kernel_launch(const char *KernelName, Ts...) {
+      // Call functions appropriate for the desired offload backend
+      // (OpenCL, CUDA, HIP, Level Zero, etc...) to enqueue kernel invocation.
+    }
+
     template<typename KernelNameType, typename KernelType>
     [[ clang::sycl_kernel_entry_point(KernelNameType) ]]
-    static void kernel_entry_point(KernelType kernel) {
-      kernel();
+    void kernel_entry_point(KernelType Kernel) {
+      Kernel();
     }
 
   public:
     template<typename KernelNameType, typename KernelType>
-    void single_task(KernelType kernel) {
-      // Call kernel_entry_point() to trigger generation of an offload
-      // kernel entry point.
-      kernel_entry_point<KernelNameType>(kernel);
-      // Call functions appropriate for the desired offload backend
-      // (OpenCL, CUDA, HIP, Level Zero, etc...).
+    void single_task(KernelType Kernel) {
+      // Call kernel_entry_point() to launch the kernel and to trigger
+      // generation of an offload kernel entry point.
+      kernel_entry_point<KernelNameType>(Kernel);
     }
   };
   } // namespace sycl
 
-A SYCL kernel is a callable object of class type that is constructed on a host,
-often via a lambda expression, and then passed to a SYCL kernel invocation
-function to be executed on an offload device. A SYCL kernel invocation function
-is responsible for copying the provided SYCL kernel object to an offload
-device and initiating a call to it. The SYCL kernel object and its data members
-constitute the parameters of an offload kernel.
-
-A SYCL kernel type is required to satisfy the device copyability requirements
-specified in section 3.13.1, "Device copyable", of the SYCL 2020 specification.
-Additionally, any data members of the kernel object type are required to satisfy
-section 4.12.4, "Rules for parameter passing to kernels". For most types, these
-rules require that the type is trivially copyable.  However, the SYCL
-specification mandates that certain special SYCL types, such as
-``sycl::accessor`` and ``sycl::stream`` be device copyable even if they are not
-trivially copyable. These types require special handling because they cannot
+A SYCL kernel object is a callable object of class type that is constructed on
+a host, often via a lambda expression, and then passed to a SYCL kernel
+invocation function to be executed on an offload device. A SYCL kernel
+invocation function is responsible for copying the provided SYCL kernel object
+to an offload device and initiating a call to it. The SYCL kernel object and
+its data members constitute the parameters of an offload kernel.
+
+A SYCL kernel object type is required to satisfy the device copyability
+requirements specified in section 3.13.1, "Device copyable", of the SYCL 2020
+specification. Additionally, any data members of the kernel object type are
+required to satisfy section 4.12.4, "Rules for parameter passing to kernels".
+For most types, these rules require that the type is trivially copyable.
+However, the SYCL specification mandates that certain special SYCL types, such
+as ``sycl::accessor`` and ``sycl::stream`` be device copyable even if they are
+not trivially copyable. These types require special handling because they cannot
 be copied to device memory as if by ``memcpy()``. Additionally, some offload
 backends, OpenCL for example, require objects of some of these types to be
 passed as individual arguments to the offload kernel.
@@ -612,7 +616,7 @@ like OpenCL):
 
 #. Identifying the offload kernel entry point to be used for the SYCL kernel.
 
-#. Deconstructing the SYCL kernel object, if necessary, to produce the set of
+#. Decomposing the SYCL kernel object, if necessary, to produce the set of
    offload kernel arguments required by the offload kernel entry point.
 
 #. Copying the offload kernel arguments to device memory.
@@ -621,17 +625,23 @@ like OpenCL):
 
 The offload kernel entry point for a SYCL kernel performs the following tasks:
 
-#. Reconstituting the SYCL kernel object, if necessary, using the offload
+#. Reconstructing the SYCL kernel object, if necessary, using the offload
    kernel parameters.
 
-#. Calling the ``operator()`` member function of the (reconstituted) SYCL kernel
+#. Calling the ``operator()`` member function of the (reconstructed) SYCL kernel
    object.
 
-The ``sycl_kernel_entry_point`` attribute automates generation of an offload
-kernel entry point that performs those latter tasks. The parameters and body of
-a function declared with the ``sycl_kernel_entry_point`` attribute specify a
-pattern from which the parameters and body of the entry point function are
-derived. Consider the following call to a SYCL kernel invocation function.
+The ``sycl_kernel_entry_point`` attribute facilitates or automates these tasks
+by generating the offload kernel entry point, generating a unique symbol name
+for it, synthesizing code for kernel argument decomposition and reconstruction,
+and synthesizing a call to a ``sycl_enqueue_kernel_launch`` function template
+with the kernel name type, kernel symbol name, and (decomposed) kernel arguments
+passed as template or function arguments.
+
+A function declared with the ``sycl_kernel_entry_point`` attribute specifies
+the parameters and body of the offload entry point function. Consider the
+following call to the ``single_task()`` SYCL kernel invocation function assuming
+an implementation similar to the one shown above.
 
 .. code-block:: c++
 
@@ -645,31 +655,33 @@ derived. Consider the following call to a SYCL kernel invocation function.
 The SYCL kernel object is the result of the lambda expression. It has two
 data members corresponding to the captures of ``sout`` and ``s``. Since one
 of these data members corresponds to a special SYCL type that must be passed
-individually as an offload kernel parameter, it is necessary to decompose the
-SYCL kernel object into its constituent parts; the offload kernel will have
-two kernel parameters. Given a SYCL implementation that uses a
-``sycl_kernel_entry_point`` attributed function like the one shown above, an
+individually as an offload kernel argument, it is necessary to decompose the
+SYCL kernel object into its constituent parts and pass them individually. An
 offload kernel entry point function will be generated that looks approximately
 as follows.
 
 .. code-block:: c++
 
   void sycl-kernel-caller-for-KN(sycl::stream sout, S s) {
-    kernel-type kernel = { sout, s );
-    kernel();
+    kernel-type Kernel = { sout, s );
+    Kernel();
   }
 
 There are a few items worthy of note:
 
 #. The name of the generated function incorporates the SYCL kernel name,
    ``KN``, that was passed as the ``KernelNameType`` template parameter to
-   ``kernel_entry_point()`` and provided as the argument to the
+   ``single_task()`` and eventually provided as the argument to the
    ``sycl_kernel_entry_point`` attribute. There is a one-to-one correspondence
    between SYCL kernel names and offload kernel entry points.
 
+#. The parameters and the call to ``Kernel()`` correspond to the definition of
+   ``kernel_entry_point()`` called by ``single_task()`` with the SYCL kernel
+   object argument decomposed and reconstructed.
+
 #. The SYCL kernel is a lambda closure type and therefore has no name;
    ``kernel-type`` is substituted above and corresponds to the ``KernelType``
-   template parameter deduced in the call to ``kernel_entry_point()``.
+   template parameter deduced in the call to ``single_task()``.
    Lambda types cannot be declared and initialized using the aggregate
    initialization syntax used above, but the intended behavior should be clear.
 
@@ -683,24 +695,55 @@ There are a few items worthy of note:
    or more parameters depending on how the SYCL library implementation defines
    these types.
 
-#. The call to ``kernel_entry_point()`` has no effect other than to trigger
-   emission of the entry point function. The statments that make up the body
-   of the function are not executed when the function is called; they are
-   only used in the generation of the entry point function.
+The call to ``kernel_entry_point()`` by ``single_task()`` is effectively
+replaced with synthesized code that looks approximately as follows.
+
+.. code-block:: c++
+
+  sycl::stream sout = Kernel.sout;
+  S s = Kernel.s;
+  sycl_enqueue_kernel_launch<KN>("kernel-symbol-name", sout, s);
+
+There are a few items worthy of note:
+
+#. The SYCL kernel object is a lambda closure type and its captures do not
+   have formal names and cannot be accessed using the member access syntax used
+   above, but the intended behavior should be clear.
+
+#. ``kernel-symbol-name`` is substituted for the actual symbol name that would
+   be generated; these names are implementation details subject to change.
+
+#. Lookup for the ``sycl_enqueue_kernel_launch()`` function template is
+   performed from the (possibly instantiated) location of the definition of
+   ``kernel_entry_point()``. If overload resolution fails, the program is
+   ill-formed. If the selected overload is a non-static member function, then
+   ``this`` is passed for the implicit object parameter.
+
+#. Function arguments passed to ``sycl_enqueue_kernel_launch()`` are passed
+   as if by ``std::forward<X>(x)``.
+
+#. The ``sycl_enqueue_kernel_launch()`` function is expected to be provided by
+   the SYCL library implementation. It is responsible for scheduling execution
+   of the generated offload kernel entry point identified by
+   ``kernel-symbol-name`` and copying the (decomposed) kernel arguments to
+   device memory, presumably via an offload backend such as OpenCL.
 
 It is not necessary for a function declared with the ``sycl_kernel_entry_point``
 attribute to be called for the offload kernel entry point to be emitted. For
 inline functions and function templates, any ODR-use will suffice. For other
 functions, an ODR-use is not required; the offload kernel entry point will be
-emitted if the function is defined.
+emitted if the function is defined. In any case, a call to the function is
+required for the synthesized call to ``sycl_enqueue_kernel_launch()`` to occur.
 
 Functions declared with the ``sycl_kernel_entry_point`` attribute are not
 limited to the simple example shown above. They may have additional template
 parameters, declare additional function parameters, and have complex control
-flow in the function body. Function parameter decomposition and reconstitution
+flow in the function body. Function parameter decomposition and reconstruction
 is performed for all function parameters. The function must abide by the
 language feature restrictions described in section 5.4, "Language restrictions
-for device functions" in the SYCL 2020 specification.
+for device functions" in the SYCL 2020 specification. If the function is a
+non-static member function, ``this`` shall not be used in a potentially
+evaluated expression.
   }];
 }
 
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 85a023435ba23..470780f87323c 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -13251,14 +13251,15 @@ def warn_sycl_external_missing_on_first_decl : Warning<
 // SYCL kernel entry point diagnostics
 def err_sycl_entry_point_invalid : Error<
   "the %0 attribute cannot be applied to a %enum_select<InvalidSKEPReason>{"
-      "%NonStaticMemberFn{non-static member function}|"
       "%VariadicFn{variadic function}|"
       "%DeletedFn{deleted function}|"
       "%DefaultedFn{defaulted function}|"
+      "%Constructor{constructor}|"
+      "%Destructor{destructor}|"
+      "%Coroutine{coroutine}|"
       "%ConstexprFn{constexpr function}|"
       "%ConstevalFn{consteval function}|"
       "%NoreturnFn{function declared with the 'noreturn' attribute}|"
-      "%Coroutine{coroutine}|"
       "%FunctionTryBlock{function defined with a function try block}"
       "}1">;
 def err_sycl_entry_point_invalid_redeclaration : Error<
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index 3f63420cae91e..cf62c468f1b4d 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -15087,6 +15087,10 @@ static SYCLKernelInfo BuildSYCLKernelInfo(ASTContext &Context,
   MC->mangleCanonicalTypeName(KernelNameType, Out);
   std::string KernelName = Out.str();
 
+  // FIXME: Diagnose kernel names that are not representable in the ordinary
+  // literal encoding. This is not necessarily the right place to add such
+  // a diagnostic.
+
   return {KernelNameType, FD, KernelName};
 }
 
diff --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp
index f4ce4a7573aab..99b4f8ae5871b 100644
--- a/clang/lib/AST/StmtPrinter.cpp
+++ b/clang/lib/AST/StmtPrinter.cpp
@@ -600,7 +600,7 @@ void StmtPrinter::VisitCapturedStmt(CapturedStmt *Node) {
 }
 
 void StmtPrinter::VisitSYCLKernelCallStmt(SYCLKernelCallStmt *Node) {
-  PrintStmt(Node->getOutlinedFunctionDecl()->getBody());
+  PrintStmt(Node->getOriginalStmt());
 }
 
 void StmtPrinter::VisitObjCAtTryStmt(ObjCAtTryStmt *Node) {
diff --git a/clang/lib/CodeGen/CGStmt.cpp b/clang/lib/CodeGen/CGStmt.cpp
index 0658ecc93d88d..9a8e84a6cc12a 100644
--- a/clang/lib/CodeGen/CGStmt.cpp
+++ b/clang/lib/CodeGen/CGStmt.cpp
@@ -19,6 +19,7 @@
 #include "clang/AST/Attr.h"
 #include "clang/AST/Expr.h"
 #include "clang/AST/Stmt.h"
+#include "clang/AST/StmtSYCL.h"
 #include "clang/AST/StmtVisitor.h"
 #include "clang/Basic/Builtins.h"
 #include "clang/Basic/DiagnosticSema.h"
@@ -543,21 +544,7 @@ bool CodeGenFunction::EmitSimpleStmt(const Stmt *S,
     EmitSEHLeaveStmt(cast<SEHLeaveStmt>(*S));
     break;
   case Stmt::SYCLKernelCallStmtClass:
-    // SYCL kernel call statements are generated as wrappers around the body
-    // of functions declared with the sycl_kernel_entry_point attribute. Such
-    // functions are used to specify how a SYCL kernel (a function object) is
-    // to be invoked; the SYCL kernel call statement contains a transformed
-    // variation of the function body and is used to generate a SYCL kernel
-    // caller function; a function that serves as the device side entry point
-    // used to execute the SYCL kernel. The sycl_kernel_entry_point attributed
-    // function is invoked by host code in order to trigger emission of the
-    // device side SYCL kernel caller function and to generate metadata needed
-    // by SYCL run-time library implementations; the function is otherwise
-    // intended to have no effect. As such, the function body is not evaluated
-    // as part of the invocation during host compilation (and the function
-    // should not be called or emitted during device compilation); the SYCL
-    // kernel call statement is thus handled as a null statement for the
-    // purpose of code generation.
+    EmitSYCLKernelCallStmt(cast<SYCLKernelCallStmt>(*S));
     break;
   }
   return true;
diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h
index f769fee227878..110ae68e2656b 100644
--- a/clang/lib/CodeGen/CodeGenFunction.h
+++ b/clang/lib/CodeGen/CodeGenFunction.h
@@ -3671,6 +3671,8 @@ class CodeGenFunction : public CodeGenTypeCache {
   LValue EmitCoyieldLValue(const CoyieldExpr *E);
   RValue EmitCoroutineIntrinsic(const CallExpr *E, unsigned int IID);
 
+  void EmitSYCLKernelCallStmt(const SYCLKernelCallStmt &S);
+
   void EnterCXXTryStmt(const CXXTryStmt &S, bool IsFnTryBlock = false);
   void ExitCXXTryStmt(const CXXTryStmt &S, bool IsFnTryBlock = false);
 
diff --git a/clang/lib/CodeGen/CodeGenSYCL.cpp b/clang/lib/CodeGen/CodeGenSYCL.cpp
index 7d66d96ad0a1b..5ad5671250a92 100644
--- a/clang/lib/CodeGen/CodeGenSYCL.cpp
+++ b/clang/lib/CodeGen/CodeGenSYCL.cpp
@@ -17,6 +17,21 @@
 using namespace clang;
 using namespace CodeGen;
 
+void CodeGenFunction::EmitSYCLKernelCallStmt(const SYCLKernelCallStmt &S) {
+  if (getLangOpts().SYCLIsDevice) {
+    // A sycl_kernel_entry_point attributed function is unlikely to be emitted
+    // during device compilation, but might be if it is ODR-used from device
+    // code that is emitted. In these cases, the function is emitted with an
+    // empty body; the original body is emitted in the offload kernel entry
+    // point and the synthesized kernel launch code is only relevant for host
+    // compilation.
+    return;
+  }
+
+  assert(getLangOpts().SYCLIsHost);
+  EmitStmt(S.getKernelLaunchStmt());
+}
+
 static void SetSYCLKernelAttributes(llvm::Function *Fn, CodeGenFunction &CGF) {
   // SYCL 2020 device language restrictions require forward progress and
   // disallow recursion.
diff --git a/clang/lib/Sema/SemaExceptionSpec.cpp b/clang/lib/Sema/SemaExceptionSpec.cpp
index 8df01a8a616c3..b996dfb405b16 100644
--- a/clang/lib/Sema/SemaExceptionSpec.cpp
+++ b/clang/lib/Sema/SemaExceptionSpec.cpp
@@ -15,6 +15,7 @@
 #include "clang/AST/Expr.h"
 #include "clang/AST/ExprCXX.h"
 #include "clang/AST/StmtObjC.h"
+#include "clang/AST/StmtSYCL.h"
 #include "clang/AST/TypeLoc.h"
 #include "clang/Basic/Diagnostic.h"
 #include "clang/Basic/SourceManager.h"
@@ -1250,6 +1251,15 @@ CanThrowResult Sema::canThrow(const Stmt *S) {
     return CT;
   }
 
+  case Stmt::SYCLKernelCallStmtClass: {
+    auto *SKCS = cast<SYCLKernelCallStmt>(S);
+    if (getLangOpts().SYCLIsDevice)
+      return canSubStmtsThrow(*this,
+                              SKCS->getOutlinedFunctionDecl()->getBody());
+    assert(getLangOpts().SYCLIsHost);
+    return canSubStmtsThrow(*this, SKCS->getKernelLaunchStmt());
+  }
+
     // ObjC message sends are like function calls, but never have exception
     // specs.
   case Expr::ObjCMessageExprClass:
@@ -1433,7 +1443,6 @@ CanThrowResult Sema::canThrow(const Stmt *S) {
   case Stmt::AttributedStmtClass:
   case Stmt::BreakStmtClass:
   case Stmt::CapturedStmtClass:
-  case Stmt::SYCLKernelCallStmtClass:
   case Stmt::CaseStmtClass:
   case Stmt::CompoundStmtClass:
   case Stmt::ContinueStmtClass:
diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp
index 280f9b1a4b42d..58fda3ebd7630 100644
--- a/clang/lib/Sema/SemaSYCL.cpp
+++ b/clang/lib/Sema/SemaSYCL.cpp
@@ -315,12 +315,15 @@ void SemaSYCL::CheckSYCLEntryPointFunctionDecl(FunctionDecl *FD) {
     }
   }
 
-  if (const auto *MD = dyn_cast<CXXMethodDecl>(FD)) {
-    if (!MD->isStatic()) {
-      Diag(SKEPAttr->getLocation(), diag::err_sycl_entry_point_invalid)
-          << SKEPAttr << diag::InvalidSKEPReason::NonStaticMemberFn;
-      SKEPAttr->setInvalidAttr();
-    }
+  if (isa<CXXConstructorDecl>(FD)) {
+    Diag(SKEPAttr->getLocation(), diag::err_sycl_entry_point_invalid)
+        << SKEPAttr << diag::InvalidSKEPReason::Constructor;
+    SKEPAttr->setInvalidAttr();
+  }
+  if (isa<CXXDestructorDecl>(FD)) {
+    Diag(SKEPAttr->getLocation(), diag::err_sycl_entry_point_invalid)
+        << SKEPAttr << diag::InvalidSKEPReason::Destructor;
+    SKEPAttr->setInvalidAttr();
   }
 
   if (FD->isVariadic()) {
@@ -389,6 +392,67 @@ void SemaSYCL::CheckSYCLEntryPointFunctionDecl(FunctionDecl *FD) {
 
 namespace {
 
+CompoundStmt *BuildSYCLKernelLaunchStmt(Sema &SemaRef, FunctionDecl *FD,
+                                        const std::string &KernelName) {
+  ASTContext &Ctx = SemaRef.getASTContext();
+  SmallVector<Stmt *> Stmts;
+
+  // Prepare a string literal that contains the kernel name in the ordinary
+  // literal encoding.
+  // FIXME: transcode the contents of KernelName from UTF-8 to the
+  // ordinary literal encoding.
+  QualType KernelNameCharTy = Ctx.CharTy.withConst();
+  llvm::APInt KernelNameSize(Ctx.getTypeSize(Ctx.getSizeType()),
+                             KernelName.size() + 1);
+  QualType KernelNameArrayTy = Ctx.getConstantArrayType(
+      KernelNameCharTy, KernelNameSize, nullptr, ArraySizeModifier::Normal, 0);
+  StringLiteral *KernelNameExpr = StringLiteral::Create(
+      Ctx, KernelName, StringLiteralKind::Ordinary,
+      /*Pascal*/ false, KernelNameArrayTy, SourceLocation());
+
+  // FIXME: An extern variable declaration with assignment to the kernel
+  // name expression is added to Stmts as a temporary measure to see results.
+  // reflected in tests. The kernel name expression will need to be passed as
+  // the first function argument in a call to sycl_enqueue_kernel_launch.
+  QualType ExternVarType = Ctx.getPointerType(Ctx.CharTy.withConst());
+  const IdentifierInfo *ExternVarName =
+      SemaRef.getPreprocessor().getIdentifierInfo("kernel_name");
+  VarDecl *ExternVarDecl = VarDecl::Create(
+      Ctx, FD, SourceLocation(), SourceLocation(), ExternVarName, ExternVarType,
+      /*TInfo*/ nullptr, SC_Extern);
+  DeclStmt *ExternVarDeclStmt = new (Ctx)
+      DeclStmt(DeclGroupRef(ExternVarDecl), SourceLocation(), SourceLocation());
+  Stmts.push_back(ExternVarDeclStmt);
+  DeclRefExpr *ExternVarDeclRef = new (Ctx) DeclRefExpr(
+      Ctx, ExternVarDecl, /*RefersToEnclosingVariableOrCapture*/ false,
+      ExternVarType, VK_LValue, SourceLocation());
+  ImplicitCastExpr *KernelNameArrayDecayExpr = new (Ctx) ImplicitCastExpr(
+      ImplicitCastExpr::OnStack, ExternVarType, CK_ArrayToPointerDecay,
+      KernelNameExpr, VK_PRValue, FPOptionsOverride());
+  BinaryOperator *AssignmentExpr = BinaryOperator::Create(
+      Ctx, ExternVarDeclRef, KernelNameArrayDecayExpr, BO_Assign, ExternVarType,
+      VK_LValue, OK_Ordinary, SourceLocation(), FPOptionsOverride());
+  Stmts.push_back(AssignmentExpr);
+
+  // Perform overload resolution for a call to an accessible (member) function
+  // template named 'sycl_enqueue_kernel_launch' from within the definition of
+  // FD where:
+  // - The kernel name type is passed as the first template argument.
+  // - Any remaining template parameters are deduced from the function arguments
+  //   or assigned by default template arguments.
+  // - 'this' is passed as the implicit function argument if 'FD' is a
+  //   non-static member function.
+  // - The name of the kernel, expressed as a string literal, is passed as the
+  //   first function argument.
+  // - The parameters of FD are forwarded as-if by 'std::forward()' as the
+  //   remaining explicit function arguments.
+  // - Any remaining function arguments are initialized by default arguments.
+  CompoundStmt *LaunchStmt = CompoundStmt::Create(
+      Ctx, Stmts, FPOptionsOverride(), SourceLocation(), SourceLocation());
+
+  return LaunchStmt;
+}
+
 // The body of a function declared with the [[sycl_kernel_entry_point]]
 // attribute is cloned and transformed to substitute references to the original
 // function parameters with references to replacement variables that stand in
@@ -432,6 +496,36 @@ class OutlinedFunctionDeclBodyInstantiator
   ParmDeclMap &MapRef;
 };
 
+OutlinedFunctionDecl *BuildSYCLKernelEntryPointOutline(Sema &SemaRef,
+                                                       FunctionDecl *FD,
+                                                       CompoundStmt *Body) {
+  using ParmDeclMap = OutlinedFunctionDeclBodyInstantiator::ParmDeclMap;
+  ParmDeclMap ParmMap;
+
+  OutlinedFunctionDecl *OFD = OutlinedFunctionDecl::Create(
+      SemaRef.getASTContext(), FD, FD->getNumParams());
+  unsigned i = 0;
+  for (ParmVarDecl *PVD : FD->parameters()) {
+    ImplicitParamDecl *IPD = ImplicitParamDecl::Create(
+        SemaRef.getASTContext(), OFD, SourceLocation(), PVD->getIdentifier(),
+        PVD->getType(), ImplicitParamKind::Other);
+    OFD->setParam(i, IPD);
+    ParmMap[PVD] = IPD;
+    ++i;
+  }
+
+  // FIXME: Diagnose (implicit or explicit) use of CXXThisExpr in potentially
+  // evaluated contexts in the function body. This is not necessarily the
+  // right place to add such a diagnostic.
+
+  OutlinedFunctionDeclBodyInstantiator OFDBodyInstantiator(SemaRef, ParmMap);
+  Stmt *OFDBody = OFDBodyInstantiator.TransformStmt(Body).get();
+  OFD->setBody(OFDBody);
+  OFD->setNothrow();
+
+  return OFD;
+}
+
 } // unnamed namespace
 
 StmtResult SemaSYCL::BuildSYCLKernelCallStmt(FunctionDecl *FD,
@@ -440,6 +534,11 @@ StmtResult SemaSYCL::BuildSYCLKernelCallStmt(FunctionDecl *FD,
   assert(!FD->isTemplated());
   assert(FD->hasPrototype());
 
+  // The current context must be the function definition context to ensure
+  // that name lookup and parameter and local variable creation are performed
+  // within the correct scope.
+  assert(SemaRef.CurContext == FD);
+
   const auto *SKEPAttr = FD->getAttr<SYCLKernelEntryPointAttr>();
   assert(SKEPAttr && "Missing sycl_kernel_entry_point attribute");
   assert(!SKEPAttr->isInvalidAttr() &&
@@ -451,29 +550,19 @@ StmtResult SemaSYCL::BuildSYCLKernelCallStmt(FunctionDecl *FD,
       getASTContext().getSYCLKernelInfo(SKEPAttr->getKernelName());
   assert(declaresSameEntity(SKI.getKernelEntryPointDecl(), FD) &&
          "SYCL kernel name conflict");
-  (void)SKI;
 
-  using ParmDeclMap = OutlinedFunctionDeclBodyInstantiator::ParmDeclMap;
-  ParmDeclMap ParmMap;
+  // Build the kernel launch statement.
+  Stmt *LaunchStmt =
+      BuildSYCLKernelLaunchStmt(SemaRef, FD, SKI.GetKernelName());
+  assert(LaunchStmt);
 
-  assert(SemaRef.CurContext == FD);
+  // Build the outline of the synthesized device entry point function.
   OutlinedFunctionDecl *OFD =
-      OutlinedFunctionDecl::Create(getASTContext(), FD, FD->getNumParams());
-  unsigned i = 0;
-  for (ParmVarDecl *PVD : FD->parameters()) {
-    ImplicitParamDecl *IPD = ImplicitParamDecl::Create(
-        getASTContext(), OFD, SourceLocation(), PVD->getIdentifier(),
-        PVD->getType(), ImplicitParamKind::Other);
-    OFD->setParam(i, IPD);
-    ParmMap[PVD] = IPD;
-    ++i;
-  }
+      BuildSYCLKernelEntryPointOutline(SemaRef, FD, Body);
+  assert(OFD);
 
-  OutlinedFunctionDeclBodyInstantiator OFDBodyInstantiator(SemaRef, ParmMap);
-  Stmt *OFDBody = OFDBodyInstantiator.TransformStmt(Body).get();
-  OFD->setBody(OFDBody);
-  OFD->setNothrow();
-  Stmt *NewBody = new (getASTContext()) SYCLKernelCallStmt(Body, OFD);
+  Stmt *NewBody =
+      new (getASTContext()) SYCLKernelCallStmt(Body, LaunchStmt, OFD);
 
   return NewBody;
 }
diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp
index a18fccb6518d2..9e8619596f789 100644
--- a/clang/lib/Serialization/ASTReaderStmt.cpp
+++ b/clang/lib/Serialization/ASTReaderStmt.cpp
@@ -543,6 +543,7 @@ void ASTStmtReader::VisitCXXReflectExpr(CXXReflectExpr *E) {
 void ASTStmtReader::VisitSYCLKernelCallStmt(SYCLKernelCallStmt *S) {
   VisitStmt(S);
   S->setOriginalStmt(cast<CompoundStmt>(Record.readSubStmt()));
+  S->setKernelLaunchStmt(cast<Stmt>(Record.readSubStmt()));
   S->setOutlinedFunctionDecl(readDeclAs<OutlinedFunctionDecl>());
 }
 
diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp
index 4fcac4d0261ab..2072bbfe8311c 100644
--- a/clang/lib/Serialization/ASTWriterStmt.cpp
+++ b/clang/lib/Serialization/ASTWriterStmt.cpp
@@ -637,6 +637,7 @@ void ASTStmtWriter::VisitCapturedStmt(CapturedStmt *S) {
 void ASTStmtWriter::VisitSYCLKernelCallStmt(SYCLKernelCallStmt *S) {
   VisitStmt(S);
   Record.AddStmt(S->getOriginalStmt());
+  Record.AddStmt(S->getKernelLaunchStmt());
   Record.AddDeclRef(S->getOutlinedFunctionDecl());
 
   Code = serialization::STMT_SYCLKERNELCALL;
diff --git a/clang/test/AST/ast-print-sycl-kernel-call.cpp b/clang/test/AST/ast-print-sycl-kernel-call.cpp
new file mode 100644
index 0000000000000..2243ee024be1a
--- /dev/null
+++ b/clang/test/AST/ast-print-sycl-kernel-call.cpp
@@ -0,0 +1,22 @@
+// RUN: %clang_cc1 -fsycl-is-host -ast-print %s -o - | FileCheck %s
+// RUN: %clang_cc1 -fsycl-is-device -ast-print %s -o - | FileCheck %s
+
+struct sycl_kernel_launcher {
+  template<typename KernelName, typename... Ts>
+  void sycl_enqueue_kernel_launch(const char *, Ts...) {}
+
+  template<typename KernelName, typename KernelType>
+  void kernel_entry_point(KernelType kernel) {
+    kernel();
+  }
+// CHECK:      template <typename KernelName, typename KernelType> void kernel_entry_point(KernelType kernel) {
+// CHECK-NEXT:     kernel();
+// CHECK-NEXT: }
+// CHECK:      template<> void kernel_entry_point<KN, (lambda at {{.*}})>((lambda at {{.*}}) kernel) {
+// CHECK-NEXT:     kernel();
+// CHECK-NEXT: }
+};
+
+void f(sycl_kernel_launcher skl) {
+  skl.kernel_entry_point<struct KN>([]{});
+}
diff --git a/clang/test/ASTSYCL/ast-dump-sycl-kernel-call-stmt.cpp b/clang/test/ASTSYCL/ast-dump-sycl-kernel-call-stmt.cpp
index e3ff3dea19514..328899ed5ce7d 100644
--- a/clang/test/ASTSYCL/ast-dump-sycl-kernel-call-stmt.cpp
+++ b/clang/test/ASTSYCL/ast-dump-sycl-kernel-call-stmt.cpp
@@ -41,6 +41,13 @@ void skep1() {
 // CHECK:      |-FunctionDecl {{.*}} skep1 'void ()'
 // CHECK-NEXT: | |-SYCLKernelCallStmt {{.*}}
 // CHECK-NEXT: | | |-CompoundStmt {{.*}}
+// CHECK-NEXT: | | |-CompoundStmt {{.*}}
+// CHECK-NEXT: | | | |-DeclStmt {{.*}}
+// CHECK-NEXT: | | | | `-VarDecl {{.*}} kernel_name 'const char *' extern
+// CHECK-NEXT: | | | `-BinaryOperator {{.*}} 'const char *' lvalue '='
+// CHECK-NEXT: | | |   |-DeclRefExpr {{.*}} 'const char *' lvalue Var {{.*}} 'kernel_name' 'const char *'
+// CHECK-NEXT: | | |   `-ImplicitCastExpr {{.*}} 'const char *' <ArrayToPointerDecay>
+// CHECK-NEXT: | | |     `-StringLiteral {{.*}} 'const char[14]' lvalue "_ZTS2KNILi1EE"
 // CHECK-NEXT: | | `-OutlinedFunctionDecl {{.*}}
 // CHECK-NEXT: | |   `-CompoundStmt {{.*}}
 // CHECK-NEXT: | `-SYCLKernelEntryPointAttr {{.*}} KN<1>
@@ -77,6 +84,13 @@ void skep2<KN<2>>(K<2>);
 // CHECK-NEXT: |   | |   | `-DeclRefExpr {{.*}} 'void () const' lvalue CXXMethod {{.*}} 'operator()' 'void () const'
 // CHECK-NEXT: |   | |   `-ImplicitCastExpr {{.*}} 'const K<2>' lvalue <NoOp>
 // CHECK-NEXT: |   | |     `-DeclRefExpr {{.*}} 'K<2>' lvalue ParmVar {{.*}} 'k' 'K<2>'
+// CHECK-NEXT: |   | |-CompoundStmt {{.*}}
+// CHECK-NEXT: |   | | |-DeclStmt {{.*}}
+// CHECK-NEXT: |   | | | `-VarDecl {{.*}} kernel_name 'const char *' extern
+// CHECK-NEXT: |   | | `-BinaryOperator {{.*}} 'const char *' lvalue '='
+// CHECK-NEXT: |   | |   |-DeclRefExpr {{.*}} 'const char *' lvalue Var {{.*}} 'kernel_name' 'const char *'
+// CHECK-NEXT: |   | |   `-ImplicitCastExpr {{.*}} 'const char *' <ArrayToPointerDecay>
+// CHECK-NEXT: |   | |     `-StringLiteral {{.*}} 'const char[14]' lvalue "_ZTS2KNILi2EE"
 // CHECK-NEXT: |   | `-OutlinedFunctionDecl {{.*}}
 // CHECK-NEXT: |   |   |-ImplicitParamDecl {{.*}} implicit used k 'K<2>'
 // CHECK-NEXT: |   |   `-CompoundStmt {{.*}}
@@ -123,6 +137,13 @@ void skep3<KN<3>>(K<3> k) {
 // CHECK-NEXT: | | |   | `-DeclRefExpr {{.*}} 'void () const' lvalue CXXMethod {{.*}} 'operator()' 'void () const'
 // CHECK-NEXT: | | |   `-ImplicitCastExpr {{.*}} 'const K<3>' lvalue <NoOp>
 // CHECK-NEXT: | | |     `-DeclRefExpr {{.*}} 'K<3>' lvalue ParmVar {{.*}} 'k' 'K<3>'
+// CHECK-NEXT: | | |-CompoundStmt {{.*}}
+// CHECK-NEXT: | | | |-DeclStmt {{.*}}
+// CHECK-NEXT: | | | | `-VarDecl {{.*}} kernel_name 'const char *' extern
+// CHECK-NEXT: | | | `-BinaryOperator {{.*}} 'const char *' lvalue '='
+// CHECK-NEXT: | | |   |-DeclRefExpr {{.*}} 'const char *' lvalue Var {{.*}} 'kernel_name' 'const char *'
+// CHECK-NEXT: | | |   `-ImplicitCastExpr {{.*}} 'const char *' <ArrayToPointerDecay>
+// CHECK-NEXT: | | |     `-StringLiteral {{.*}} 'const char[14]' lvalue "_ZTS2KNILi3EE"
 // CHECK-NEXT: | | `-OutlinedFunctionDecl {{.*}}
 // CHECK-NEXT: | |   |-ImplicitParamDecl {{.*}} implicit used k 'K<3>'
 // CHECK-NEXT: | |   `-CompoundStmt {{.*}}
@@ -152,6 +173,13 @@ void skep4(K<4> k, int p1, int p2) {
 // CHECK-NEXT: | | |   | `-DeclRefExpr {{.*}} 'int' lvalue ParmVar {{.*}} 'p1' 'int'
 // CHECK-NEXT: | | |   `-ImplicitCastExpr {{.*}} 'int' <LValueToRValue>
 // CHECK-NEXT: | | |     `-DeclRefExpr {{.*}} 'int' lvalue ParmVar {{.*}} 'p2' 'int'
+// CHECK-NEXT: | | |-CompoundStmt {{.*}}
+// CHECK-NEXT: | | | |-DeclStmt {{.*}}
+// CHECK-NEXT: | | | | `-VarDecl {{.*}} kernel_name 'const char *' extern
+// CHECK-NEXT: | | | `-BinaryOperator {{.*}} 'const char *' lvalue '='
+// CHECK-NEXT: | | |   |-DeclRefExpr {{.*}} 'const char *' lvalue Var {{.*}} 'kernel_name' 'const char *'
+// CHECK-NEXT: | | |   `-ImplicitCastExpr {{.*}} 'const char *' <ArrayToPointerDecay>
+// CHECK-NEXT: | | |     `-StringLiteral {{.*}} 'const char[14]' lvalue "_ZTS2KNILi4EE"
 // CHECK-NEXT: | | `-OutlinedFunctionDecl {{.*}}
 // CHECK-NEXT: | |   |-ImplicitParamDecl {{.*}} implicit used k 'K<4>'
 // CHECK-NEXT: | |   |-ImplicitParamDecl {{.*}} implicit used p1 'int'
@@ -182,7 +210,14 @@ void skep5(int unused1, K<5> k, int unused2, int p, int unused3) {
 // CHECK-NEXT: | |-ParmVarDecl {{.*}} unused3 'int'
 // CHECK-NEXT: | |-SYCLKernelCallStmt {{.*}}
 // CHECK-NEXT: | | |-CompoundStmt {{.*}}
-// CHECK:      | | `-OutlinedFunctionDecl {{.*}}
+// CHECK:      | | |-CompoundStmt {{.*}}
+// CHECK-NEXT: | | | |-DeclStmt {{.*}}
+// CHECK-NEXT: | | | | `-VarDecl {{.*}} kernel_name 'const char *' extern
+// CHECK-NEXT: | | | `-BinaryOperator {{.*}} 'const char *' lvalue '='
+// CHECK-NEXT: | | |   |-DeclRefExpr {{.*}} 'const char *' lvalue Var {{.*}} 'kernel_name' 'const char *'
+// CHECK-NEXT: | | |   `-ImplicitCastExpr {{.*}} 'const char *' <ArrayToPointerDecay>
+// CHECK-NEXT: | | |     `-StringLiteral {{.*}} 'const char[14]' lvalue "_ZTS2KNILi5EE"
+// CHECK-NEXT: | | `-OutlinedFunctionDecl {{.*}}
 // CHECK-NEXT: | |   |-ImplicitParamDecl {{.*}} implicit unused1 'int'
 // CHECK-NEXT: | |   |-ImplicitParamDecl {{.*}} implicit used k 'K<5>'
 // CHECK-NEXT: | |   |-ImplicitParamDecl {{.*}} implicit unused2 'int'
@@ -227,6 +262,13 @@ void skep6(const S6 &k) {
 // CHECK-NEXT: | | |   |-ImplicitCastExpr {{.*}} 'void (*)() const' <FunctionToPointerDecay>
 // CHECK-NEXT: | | |   | `-DeclRefExpr {{.*}} 'void () const' lvalue CXXMethod {{.*}} 'operator()' 'void () const'
 // CHECK-NEXT: | | |   `-DeclRefExpr {{.*}} 'const S6' lvalue ParmVar {{.*}} 'k' 'const S6 &'
+// CHECK-NEXT: | | |-CompoundStmt {{.*}}
+// CHECK-NEXT: | | | |-DeclStmt {{.*}}
+// CHECK-NEXT: | | | | `-VarDecl {{.*}} kernel_name 'const char *' extern
+// CHECK-NEXT: | | | `-BinaryOperator {{.*}} 'const char *' lvalue '='
+// CHECK-NEXT: | | |   |-DeclRefExpr {{.*}} 'const char *' lvalue Var {{.*}} 'kernel_name' 'const char *'
+// CHECK-NEXT: | | |   `-ImplicitCastExpr {{.*}} 'const char *' <ArrayToPointerDecay>
+// CHECK-NEXT: | | |     `-StringLiteral {{.*}} 'const char[14]' lvalue "_ZTS2KNILi6EE"
 // CHECK-NEXT: | | `-OutlinedFunctionDecl {{.*}}
 // CHECK-NEXT: | |   |-ImplicitParamDecl {{.*}} implicit used k 'const S6 &'
 // CHECK-NEXT: | |   `-CompoundStmt {{.*}}
@@ -260,6 +302,13 @@ void skep7(S7 k) {
 // CHECK-NEXT: | | |   | `-DeclRefExpr {{.*}} 'void () const' lvalue CXXMethod {{.*}} 'operator()' 'void () const'
 // CHECK-NEXT: | | |   `-ImplicitCastExpr {{.*}} 'const S7' lvalue <NoOp>
 // CHECK-NEXT: | | |     `-DeclRefExpr {{.*}} 'S7' lvalue ParmVar {{.*}} 'k' 'S7'
+// CHECK-NEXT: | | |-CompoundStmt {{.*}}
+// CHECK-NEXT: | | | |-DeclStmt {{.*}}
+// CHECK-NEXT: | | | | `-VarDecl {{.*}} kernel_name 'const char *' extern
+// CHECK-NEXT: | | | `-BinaryOperator {{.*}} 'const char *' lvalue '='
+// CHECK-NEXT: | | |   |-DeclRefExpr {{.*}} 'const char *' lvalue Var {{.*}} 'kernel_name' 'const char *'
+// CHECK-NEXT: | | |   `-ImplicitCastExpr {{.*}} 'const char *' <ArrayToPointerDecay>
+// CHECK-NEXT: | | |     `-StringLiteral {{.*}} 'const char[14]' lvalue "_ZTS2KNILi7EE"
 // CHECK-NEXT: | | `-OutlinedFunctionDecl {{.*}}
 // CHECK-NEXT: | |   |-ImplicitParamDecl {{.*}} implicit used k 'S7'
 // CHECK-NEXT: | |   `-CompoundStmt {{.*}}
diff --git a/clang/test/CodeGenSYCL/kernel-caller-entry-point.cpp b/clang/test/CodeGenSYCL/kernel-caller-entry-point.cpp
index 67b53f3ae81cf..2c072014bbe42 100644
--- a/clang/test/CodeGenSYCL/kernel-caller-entry-point.cpp
+++ b/clang/test/CodeGenSYCL/kernel-caller-entry-point.cpp
@@ -55,8 +55,8 @@ int main() {
 // Verify that SYCL kernel caller functions are not emitted during host
 // compilation.
 //
-// CHECK-HOST-NOT: _ZTS26single_purpose_kernel_name
-// CHECK-HOST-NOT: _ZTSZ4mainE18lambda_kernel_name
+// CHECK-HOST-NOT: define {{.*}} @_ZTS26single_purpose_kernel_name
+// CHECK-HOST-NOT: define {{.*}} @_ZTSZ4mainE18lambda_kernel_name
 
 // Verify that sycl_kernel_entry_point attributed functions are not emitted
 // during device compilation.
@@ -64,13 +64,13 @@ int main() {
 // CHECK-DEVICE-NOT: single_purpose_kernel_task
 // CHECK-DEVICE-NOT: kernel_single_task
 
-// Verify that no code is generated for the bodies of sycl_kernel_entry_point
-// attributed functions during host compilation. ODR-use of these functions may
-// require them to be emitted, but they have no effect if called.
+// Verify that kernel launch code is generated for sycl_kernel_entry_point
+// attributed functions during host compilation.
 //
 // CHECK-HOST-LINUX:      define dso_local void @_Z26single_purpose_kernel_task21single_purpose_kernel() #{{[0-9]+}} {
 // CHECK-HOST-LINUX-NEXT: entry:
 // CHECK-HOST-LINUX-NEXT:   %kernelFunc = alloca %struct.single_purpose_kernel, align 1
+// CHECK-HOST-LINUX-NEXT:   store ptr @.str, ptr @kernel_name, align 8
 // CHECK-HOST-LINUX-NEXT:   ret void
 // CHECK-HOST-LINUX-NEXT: }
 //
@@ -79,6 +79,7 @@ int main() {
 // CHECK-HOST-LINUX-NEXT:   %kernelFunc = alloca %class.anon, align 4
 // CHECK-HOST-LINUX-NEXT:   %coerce.dive = getelementptr inbounds nuw %class.anon, ptr %kernelFunc, i32 0, i32 0
 // CHECK-HOST-LINUX-NEXT:   store i32 %kernelFunc.coerce, ptr %coerce.dive, align 4
+// CHECK-HOST-LINUX-NEXT:   store ptr @.str.1, ptr @kernel_name, align 8
 // CHECK-HOST-LINUX-NEXT:   ret void
 // CHECK-HOST-LINUX-NEXT: }
 //
@@ -87,6 +88,7 @@ int main() {
 // CHECK-HOST-WINDOWS-NEXT:   %kernelFunc = alloca %struct.single_purpose_kernel, align 1
 // CHECK-HOST-WINDOWS-NEXT:   %coerce.dive = getelementptr inbounds nuw %struct.single_purpose_kernel, ptr %kernelFunc, i32 0, i32 0
 // CHECK-HOST-WINDOWS-NEXT:   store i8 %kernelFunc.coerce, ptr %coerce.dive, align 1
+// CHECK-HOST-WINDOWS-NEXT:   store ptr @"??_C at _0CB@KFIJOMLB at _ZTS26single_purpose_kernel_name@", ptr @"?kernel_name@?0??single_purpose_kernel_task@@YAXUsingle_purpose_kernel@@@Z at 3PEBDEB", align 8
 // CHECK-HOST-WINDOWS-NEXT:   ret void
 // CHECK-HOST-WINDOWS-NEXT: }
 //
@@ -95,6 +97,7 @@ int main() {
 // CHECK-HOST-WINDOWS-NEXT:   %kernelFunc = alloca %class.anon, align 4
 // CHECK-HOST-WINDOWS-NEXT:   %coerce.dive = getelementptr inbounds nuw %class.anon, ptr %kernelFunc, i32 0, i32 0
 // CHECK-HOST-WINDOWS-NEXT:   store i32 %kernelFunc.coerce, ptr %coerce.dive, align 4
+// CHECK-HOST-WINDOWS-NEXT:   store ptr @"??_C at _0BC@NHCDOLAA at _ZTSZ4mainEUlT_E_?$AA@", ptr @"?kernel_name@?0???$kernel_single_task at V<lambda_1>@?0??main@@9 at V1?0??2 at 9@@@YAXV<lambda_1>@?0??main@@9@@Z at 3PEBDEB", align 8
 // CHECK-HOST-WINDOWS-NEXT:   ret void
 // CHECK-HOST-WINDOWS-NEXT: }
 
diff --git a/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-appertainment.cpp b/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-appertainment.cpp
index 9aba284145fcb..3f07feb87c9a1 100644
--- a/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-appertainment.cpp
+++ b/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-appertainment.cpp
@@ -1,5 +1,8 @@
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++17 -fsyntax-only -fsycl-is-host -fcxx-exceptions -verify %s
 // RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++17 -fsyntax-only -fsycl-is-device -verify %s
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++20 -fsyntax-only -fsycl-is-host -fcxx-exceptions -verify %s
 // RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++20 -fsyntax-only -fsycl-is-device -verify %s
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++23 -fsyntax-only -fsycl-is-host -fcxx-exceptions -verify %s
 // RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++23 -fsyntax-only -fsycl-is-device -verify %s
 
 // These tests validate appertainment for the sycl_kernel_entry_point attribute.
@@ -131,6 +134,16 @@ struct S15 {
   static T ok15();
 };
 
+struct S16 {
+  // Non-static member function declaration.
+  [[clang::sycl_kernel_entry_point(KN<16>)]]
+  void ok16();
+};
+
+#if __cplusplus >= 202302L
+auto ok17 = [] [[clang::sycl_kernel_entry_point(KN<17>)]] -> void {};
+#endif
+
 
 ////////////////////////////////////////////////////////////////////////////////
 // Invalid declarations.
@@ -163,13 +176,6 @@ struct B2 {
   static int bad2;
 };
 
-struct B3 {
-  // Non-static member function declaration.
-  // expected-error at +1 {{the 'clang::sycl_kernel_entry_point' attribute cannot be applied to a non-static member function}}
-  [[clang::sycl_kernel_entry_point(BADKN<3>)]]
-  void bad3();
-};
-
 // expected-error at +1 {{'clang::sycl_kernel_entry_point' attribute only applies to functions}}
 namespace [[clang::sycl_kernel_entry_point(BADKN<4>)]] bad4 {}
 
@@ -244,13 +250,13 @@ void bad19() {
 #endif
 
 struct B20 {
-  // expected-error at +1 {{the 'clang::sycl_kernel_entry_point' attribute cannot be applied to a non-static member function}}
+  // expected-error at +1 {{the 'clang::sycl_kernel_entry_point' attribute cannot be applied to a constructor}}
   [[clang::sycl_kernel_entry_point(BADKN<20>)]]
   B20();
 };
 
 struct B21 {
-  // expected-error at +1 {{the 'clang::sycl_kernel_entry_point' attribute cannot be applied to a non-static member function}}
+  // expected-error at +1 {{the 'clang::sycl_kernel_entry_point' attribute cannot be applied to a destructor}}
   [[clang::sycl_kernel_entry_point(BADKN<21>)]]
   ~B21();
 };
@@ -337,11 +343,6 @@ struct B34 {
   [[noreturn]] friend void bad34() {}
 };
 
-#if __cplusplus >= 202302L
-// expected-error at +1 {{the 'clang::sycl_kernel_entry_point' attribute cannot be applied to a non-static member function}}
-auto bad35 = [] [[clang::sycl_kernel_entry_point(BADKN<35>)]] -> void {};
-#endif
-
 #if __cplusplus >= 202302L
 // expected-error at +1 {{the 'clang::sycl_kernel_entry_point' attribute only applies to functions with a non-deduced 'void' return type}}
 auto bad36 = [] [[clang::sycl_kernel_entry_point(BADKN<36>)]] static {};
diff --git a/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-grammar.cpp b/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-grammar.cpp
index 8f81fa218c171..fd1f00ae05d7a 100644
--- a/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-grammar.cpp
+++ b/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-grammar.cpp
@@ -1,4 +1,6 @@
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++17 -fsyntax-only -fsycl-is-host -verify %s
 // RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++17 -fsyntax-only -fsycl-is-device -verify %s
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++20 -fsyntax-only -fsycl-is-host -verify %s
 // RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++20 -fsyntax-only -fsycl-is-device -verify %s
 
 // These tests validate parsing of the sycl_kernel_entry_point argument list
diff --git a/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-kernel-name.cpp b/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-kernel-name.cpp
index c7b83932fefe6..5a3b43be66daf 100644
--- a/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-kernel-name.cpp
+++ b/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-kernel-name.cpp
@@ -1,4 +1,6 @@
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++17 -fsyntax-only -fsycl-is-host -verify %s
 // RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++17 -fsyntax-only -fsycl-is-device -verify %s
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++20 -fsyntax-only -fsycl-is-host -verify %s
 // RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++20 -fsyntax-only -fsycl-is-device -verify %s
 
 // These tests validate that the kernel name type argument provided to the
diff --git a/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-sfinae.cpp b/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-sfinae.cpp
index 4c61570419629..3689adaab9b5b 100644
--- a/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-sfinae.cpp
+++ b/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-sfinae.cpp
@@ -1,4 +1,6 @@
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++17 -fsyntax-only -fsycl-is-host -verify %s
 // RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++17 -fsyntax-only -fsycl-is-device -verify %s
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++20 -fsyntax-only -fsycl-is-host -verify %s
 // RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++20 -fsyntax-only -fsycl-is-device -verify %s
 
 // These tests are intended to validate that a sycl_kernel_entry_point attribute

>From 29ddf0c64da6a532d33a10a207dd4dff5c2909cf Mon Sep 17 00:00:00 2001
From: Tom Honermann <tom.honermann at intel.com>
Date: Sat, 16 Aug 2025 10:54:45 -0700
Subject: [PATCH 02/29] Add diagnostics for use of 'this' in a potentially
 evaluated expression.

---
 .../clang/Basic/DiagnosticSemaKinds.td        |   3 +
 clang/lib/Sema/SemaSYCL.cpp                   |  19 +-
 .../sycl-kernel-entry-point-attr-this.cpp     | 183 ++++++++++++++++++
 3 files changed, 202 insertions(+), 3 deletions(-)
 create mode 100644 clang/test/SemaSYCL/sycl-kernel-entry-point-attr-this.cpp

diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 470780f87323c..78e33ab1031e5 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -13265,6 +13265,9 @@ def err_sycl_entry_point_invalid : Error<
 def err_sycl_entry_point_invalid_redeclaration : Error<
   "the %0 kernel name argument does not match prior"
   " declaration%diff{: $ vs $|}1,2">;
+def err_sycl_entry_point_invalid_this : Error<
+  "'this' cannot be%select{| implicitly}0 used in a potentially evaluated"
+  " expression in the body of a function declared with the %1 attribute">;
 def err_sycl_kernel_name_conflict : Error<
   "the %0 kernel name argument conflicts with a previous declaration">;
 def warn_sycl_kernel_name_not_a_class_type : Warning<
diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp
index 58fda3ebd7630..440200e7877c4 100644
--- a/clang/lib/Sema/SemaSYCL.cpp
+++ b/clang/lib/Sema/SemaSYCL.cpp
@@ -463,9 +463,10 @@ class OutlinedFunctionDeclBodyInstantiator
 public:
   using ParmDeclMap = llvm::DenseMap<ParmVarDecl *, VarDecl *>;
 
-  OutlinedFunctionDeclBodyInstantiator(Sema &S, ParmDeclMap &M)
+  OutlinedFunctionDeclBodyInstantiator(Sema &S, ParmDeclMap &M,
+                                       FunctionDecl *FD)
       : TreeTransform<OutlinedFunctionDeclBodyInstantiator>(S), SemaRef(S),
-        MapRef(M) {}
+        MapRef(M), FD(FD) {}
 
   // A new set of AST nodes is always required.
   bool AlwaysRebuild() { return true; }
@@ -491,9 +492,20 @@ class OutlinedFunctionDeclBodyInstantiator
     return DRE;
   }
 
+  // Diagnose CXXThisExpr in a potentially evaluated expression.
+  ExprResult TransformCXXThisExpr(CXXThisExpr *CTE) {
+    if (SemaRef.currentEvaluationContext().isPotentiallyEvaluated()) {
+      SemaRef.Diag(CTE->getExprLoc(), diag::err_sycl_entry_point_invalid_this)
+          << (CTE->isImplicitCXXThis() ? /* implicit */ 1 : /* empty */ 0)
+          << FD->getAttr<SYCLKernelEntryPointAttr>();
+    }
+    return CTE;
+  }
+
 private:
   Sema &SemaRef;
   ParmDeclMap &MapRef;
+  FunctionDecl *FD;
 };
 
 OutlinedFunctionDecl *BuildSYCLKernelEntryPointOutline(Sema &SemaRef,
@@ -518,7 +530,8 @@ OutlinedFunctionDecl *BuildSYCLKernelEntryPointOutline(Sema &SemaRef,
   // evaluated contexts in the function body. This is not necessarily the
   // right place to add such a diagnostic.
 
-  OutlinedFunctionDeclBodyInstantiator OFDBodyInstantiator(SemaRef, ParmMap);
+  OutlinedFunctionDeclBodyInstantiator OFDBodyInstantiator(SemaRef, ParmMap,
+                                                           FD);
   Stmt *OFDBody = OFDBodyInstantiator.TransformStmt(Body).get();
   OFD->setBody(OFDBody);
   OFD->setNothrow();
diff --git a/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-this.cpp b/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-this.cpp
new file mode 100644
index 0000000000000..fc0640e1900cb
--- /dev/null
+++ b/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-this.cpp
@@ -0,0 +1,183 @@
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsyntax-only -std=c++17 -fsycl-is-host -verify %s
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsyntax-only -std=c++17 -fsycl-is-device -verify %s
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsyntax-only -std=c++20 -fsycl-is-host -verify -DCXX20 %s
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsyntax-only -std=c++20 -fsycl-is-device -verify -DCXX20 %s
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsyntax-only -std=c++23 -fsycl-is-host -verify -DCXX23 %s
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsyntax-only -std=c++23 -fsycl-is-device -verify -DCXX23 %s
+
+// These tests validate diagnostics for invalid use of 'this' in the body of
+// a function declared with the sycl_kernel_entry_point attribute.
+
+
+template<typename T> struct remove_reference_t {
+  using type = T;
+};
+template<typename T> struct remove_reference_t<T&> {
+  using type = T;
+};
+
+namespace std {
+struct type_info {
+  virtual ~type_info();
+};
+} // namespace std
+
+////////////////////////////////////////////////////////////////////////////////
+// Valid declarations.
+////////////////////////////////////////////////////////////////////////////////
+template<int, int=0> struct KN;
+
+struct S1 {
+  [[clang::sycl_kernel_entry_point(KN<1>)]] void ok1() {
+    (void)sizeof(this);
+  }
+};
+
+struct S2 {
+  [[clang::sycl_kernel_entry_point(KN<2>)]] void ok2() {
+    (void)noexcept(this);
+  }
+};
+
+struct S3 {
+  [[clang::sycl_kernel_entry_point(KN<3>)]] void ok3() {
+    decltype(this) x = nullptr;
+  }
+};
+
+struct S4 {
+  static void smf();
+  [[clang::sycl_kernel_entry_point(KN<4>)]] void ok4() {
+    remove_reference_t<decltype(*this)>::type::smf();
+  }
+};
+
+struct S5 {
+  int dm;
+  void mf();
+  [[clang::sycl_kernel_entry_point(KN<5>)]] void ok5() {
+    (void)typeid(*this); // S5 is not abstract, so 'this' is not evaluated.
+    (void)typeid(dm);    // 'int' is not an abstract class type; implicit 'this' is not evaluated.
+    (void)typeid(mf());  // 'void' is not an abstract class type; implicit 'this' is not evaluated.
+  }
+};
+
+template<typename KN, bool B>
+struct S6 {
+  void mf() noexcept(B);
+  [[clang::sycl_kernel_entry_point(KN)]] void ok6() noexcept(noexcept(mf())) {}
+};
+template void S6<KN<6,0>, false>::ok6();
+template void S6<KN<6,1>, true>::ok6();
+
+template<typename KN, bool B>
+struct S7 {
+  void mf() noexcept(B);
+  [[clang::sycl_kernel_entry_point(KN)]] void ok7() noexcept(noexcept(this->mf())) {}
+};
+template void S7<KN<7,0>, false>::ok7();
+template void S7<KN<7,1>, true>::ok7();
+
+#if defined(CXX20)
+template<typename KN, typename T>
+struct S8 {
+  void mf(T);
+  [[clang::sycl_kernel_entry_point(KN)]] void ok8() requires(requires { mf(1); }) {}
+};
+template void S8<KN<8>, int>::ok8();
+
+template<typename KN, typename T>
+struct S9 {
+  void mf(T);
+  [[clang::sycl_kernel_entry_point(KN)]] void ok9() requires(requires { this->mf(1); }) {}
+};
+template void S9<KN<9>, int>::ok9();
+#endif
+
+#if defined(CXX23)
+struct S10 {
+  [[clang::sycl_kernel_entry_point(KN<10>)]] void ok10(this S10 self) {
+    (void)self;
+  }
+};
+#endif
+
+
+////////////////////////////////////////////////////////////////////////////////
+// Invalid declarations.
+////////////////////////////////////////////////////////////////////////////////
+
+template<int, int=0> struct BADKN;
+
+// expected-error at +3 {{'this' cannot be used in a potentially evaluated expression in the body of a function declared with the 'clang::sycl_kernel_entry_point' attribute}}
+struct B1 {
+  [[clang::sycl_kernel_entry_point(BADKN<1>)]] void bad1() {
+    (void)this;
+  }
+};
+
+// expected-error at +4 {{'this' cannot be implicitly used in a potentially evaluated expression in the body of a function declared with the 'clang::sycl_kernel_entry_point' attribute}}
+struct B2 {
+  int dm;
+  [[clang::sycl_kernel_entry_point(BADKN<2>)]] void bad2() {
+    (void)dm;
+  }
+};
+
+// expected-error at +4 {{'this' cannot be implicitly used in a potentially evaluated expression in the body of a function declared with the 'clang::sycl_kernel_entry_point' attribute}}
+struct B3 {
+  void mf();
+  [[clang::sycl_kernel_entry_point(BADKN<3>)]] void bad3() {
+    (void)mf();
+  }
+};
+
+// expected-error at +4 {{'this' cannot be used in a potentially evaluated expression in the body of a function declared with the 'clang::sycl_kernel_entry_point' attribute}}
+struct B4 {
+  virtual void vmf() = 0;
+  [[clang::sycl_kernel_entry_point(BADKN<4>)]] void bad4() {
+    (void)typeid(*this); // B4 is abstract, so 'this' is evaluated.
+  }
+};
+
+// A diagnostic is not currently issued for uninstantiated definitions. In this
+// case, a declaration is instantiated, but a definition isn't. A diagnostic
+// will be issued if a definition is instantiated (as the next test exercises).
+struct B5 {
+  template<typename KN>
+  [[clang::sycl_kernel_entry_point(KN)]] void bad5() {
+    (void)this;
+  }
+};
+extern template void B5::bad5<BADKN<5>>();
+
+// expected-error at +4 {{'this' cannot be used in a potentially evaluated expression in the body of a function declared with the 'clang::sycl_kernel_entry_point' attribute}}
+struct B6 {
+  template<typename KN>
+  [[clang::sycl_kernel_entry_point(KN)]] void bad6() {
+    (void)this;
+  }
+};
+// expected-note at +1 {{in instantiation of function template specialization 'B6::bad6<BADKN<6>>' requested here}}
+template void B6::bad6<BADKN<6>>();
+
+// A diagnostic is not currently issued for uninstantiated definitions. In this
+// case, a declaration is instantiated, but a definition isn't. A diagnostic
+// will be issued if a definition is instantiated (as the next test exercises).
+template<typename KN>
+struct B7 {
+  [[clang::sycl_kernel_entry_point(KN)]] void bad7() {
+    (void)this;
+  }
+};
+extern template void B7<BADKN<7>>::bad7();
+
+// expected-error at +4 {{'this' cannot be used in a potentially evaluated expression in the body of a function declared with the 'clang::sycl_kernel_entry_point' attribute}}
+template<typename KN>
+struct B8 {
+  [[clang::sycl_kernel_entry_point(KN)]] void bad8() {
+    (void)this;
+  }
+};
+// expected-note at +1 {{in instantiation of member function 'B8<BADKN<8>>::bad8' requested here}}
+template void B8<BADKN<8>>::bad8();

>From 35bf9ee1e293f7b983b55a126150ca030aa97958 Mon Sep 17 00:00:00 2001
From: Tom Honermann <tom.honermann at intel.com>
Date: Sat, 16 Aug 2025 11:01:00 -0700
Subject: [PATCH 03/29] Remove stale FIXME comment regarding diagnostics for
 'this'.

---
 clang/lib/Sema/SemaSYCL.cpp | 4 ----
 1 file changed, 4 deletions(-)

diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp
index 440200e7877c4..2f70025ec34fc 100644
--- a/clang/lib/Sema/SemaSYCL.cpp
+++ b/clang/lib/Sema/SemaSYCL.cpp
@@ -526,10 +526,6 @@ OutlinedFunctionDecl *BuildSYCLKernelEntryPointOutline(Sema &SemaRef,
     ++i;
   }
 
-  // FIXME: Diagnose (implicit or explicit) use of CXXThisExpr in potentially
-  // evaluated contexts in the function body. This is not necessarily the
-  // right place to add such a diagnostic.
-
   OutlinedFunctionDeclBodyInstantiator OFDBodyInstantiator(SemaRef, ParmMap,
                                                            FD);
   Stmt *OFDBody = OFDBodyInstantiator.TransformStmt(Body).get();

>From a1d9611da858cf28b6664d3da949862bd252d895 Mon Sep 17 00:00:00 2001
From: Tom Honermann <tom.honermann at intel.com>
Date: Sun, 17 Aug 2025 18:32:54 -0700
Subject: [PATCH 04/29] Add tests for kernel name character encoding concerns.

---
 clang/lib/AST/ASTContext.cpp                  |  4 --
 clang/lib/Sema/SemaSYCL.cpp                   |  5 +-
 .../ast-dump-sycl-kernel-call-stmt.cpp        | 21 ++++++
 .../CodeGenSYCL/kernel-caller-entry-point.cpp | 65 ++++++++++++++++++-
 4 files changed, 86 insertions(+), 9 deletions(-)

diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index cf62c468f1b4d..3f63420cae91e 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -15087,10 +15087,6 @@ static SYCLKernelInfo BuildSYCLKernelInfo(ASTContext &Context,
   MC->mangleCanonicalTypeName(KernelNameType, Out);
   std::string KernelName = Out.str();
 
-  // FIXME: Diagnose kernel names that are not representable in the ordinary
-  // literal encoding. This is not necessarily the right place to add such
-  // a diagnostic.
-
   return {KernelNameType, FD, KernelName};
 }
 
diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp
index 2f70025ec34fc..a6473e14fd604 100644
--- a/clang/lib/Sema/SemaSYCL.cpp
+++ b/clang/lib/Sema/SemaSYCL.cpp
@@ -397,10 +397,7 @@ CompoundStmt *BuildSYCLKernelLaunchStmt(Sema &SemaRef, FunctionDecl *FD,
   ASTContext &Ctx = SemaRef.getASTContext();
   SmallVector<Stmt *> Stmts;
 
-  // Prepare a string literal that contains the kernel name in the ordinary
-  // literal encoding.
-  // FIXME: transcode the contents of KernelName from UTF-8 to the
-  // ordinary literal encoding.
+  // Prepare a string literal that contains the kernel name.
   QualType KernelNameCharTy = Ctx.CharTy.withConst();
   llvm::APInt KernelNameSize(Ctx.getTypeSize(Ctx.getSizeType()),
                              KernelName.size() + 1);
diff --git a/clang/test/ASTSYCL/ast-dump-sycl-kernel-call-stmt.cpp b/clang/test/ASTSYCL/ast-dump-sycl-kernel-call-stmt.cpp
index 328899ed5ce7d..cc26d1d195dde 100644
--- a/clang/test/ASTSYCL/ast-dump-sycl-kernel-call-stmt.cpp
+++ b/clang/test/ASTSYCL/ast-dump-sycl-kernel-call-stmt.cpp
@@ -319,6 +319,27 @@ void skep7(S7 k) {
 // CHECK-NEXT: | |         `-DeclRefExpr {{.*}} 'S7' lvalue ImplicitParam {{.*}} 'k' 'S7'
 // CHECK-NEXT: | `-SYCLKernelEntryPointAttr {{.*}} KN<7>
 
+// Symbol names generated for the kernel entry point function should be
+// representable in the ordinary literal encoding even when the kernel name
+// type is named with esoteric characters.
+struct \u03b4\u03c4\u03c7; // Delta Tau Chi (δτχ)
+struct S8 {
+  void operator()() const;
+};
+[[clang::sycl_kernel_entry_point(\u03b4\u03c4\u03c7)]]
+void skep8(S8 k) {
+  k();
+}
+// CHECK:      |-FunctionDecl {{.*}} skep8 'void (S8)'
+// CHECK-NEXT: | |-ParmVarDecl {{.*}} used k 'S8'
+// CHECK-NEXT: | |-SYCLKernelCallStmt {{.*}}
+// CHECK-NEXT: | | |-CompoundStmt {{.*}}
+// CHECK:      | | |-CompoundStmt {{.*}}
+// CHECK:      | | |   `-ImplicitCastExpr {{.*}} 'const char *' <ArrayToPointerDecay>
+// CHECK-NEXT: | | |     `-StringLiteral {{.*}} 'const char[12]' lvalue "_ZTS6\316\264\317\204\317\207"
+// CHECK:      | | `-OutlinedFunctionDecl {{.*}}
+// CHECK:      | `-SYCLKernelEntryPointAttr {{.*}}
+
 
 void the_end() {}
 // CHECK:      `-FunctionDecl {{.*}} the_end 'void ()'
diff --git a/clang/test/CodeGenSYCL/kernel-caller-entry-point.cpp b/clang/test/CodeGenSYCL/kernel-caller-entry-point.cpp
index 2c072014bbe42..3247a328ebbd3 100644
--- a/clang/test/CodeGenSYCL/kernel-caller-entry-point.cpp
+++ b/clang/test/CodeGenSYCL/kernel-caller-entry-point.cpp
@@ -44,19 +44,24 @@ void kernel_single_task(KernelType kernelFunc) {
   kernelFunc(42);
 }
 
+// Exercise code gen with kernel name types named with esoteric characters.
+struct \u03b4\u03c4\u03c7; // Delta Tau Chi (δτχ)
+
 int main() {
   single_purpose_kernel obj;
   single_purpose_kernel_task(obj);
   int capture;
   auto lambda = [=](auto) { (void) capture; };
   kernel_single_task<decltype(lambda)>(lambda);
+  kernel_single_task<\u03b4\u03c4\u03c7>([](int){});
 }
 
 // Verify that SYCL kernel caller functions are not emitted during host
 // compilation.
 //
 // CHECK-HOST-NOT: define {{.*}} @_ZTS26single_purpose_kernel_name
-// CHECK-HOST-NOT: define {{.*}} @_ZTSZ4mainE18lambda_kernel_name
+// CHECK-HOST-NOT: define {{.*}} @_ZTSZ4mainEUlT_E_
+// CHECK-HOST-NOT: define {{.*}} @"_ZTS6\CE\B4\CF\84\CF\87"
 
 // Verify that sycl_kernel_entry_point attributed functions are not emitted
 // during device compilation.
@@ -67,6 +72,10 @@ int main() {
 // Verify that kernel launch code is generated for sycl_kernel_entry_point
 // attributed functions during host compilation.
 //
+// CHECK-HOST-LINUX:      @.str = private unnamed_addr constant [33 x i8] c"_ZTS26single_purpose_kernel_name\00", align 1
+// CHECK-HOST-LINUX:      @.str.1 = private unnamed_addr constant [18 x i8] c"_ZTSZ4mainEUlT_E_\00", align 1
+// CHECK-HOST-LINUX:      @.str.2 = private unnamed_addr constant [12 x i8] c"_ZTS6\CE\B4\CF\84\CF\87\00", align 1
+//
 // CHECK-HOST-LINUX:      define dso_local void @_Z26single_purpose_kernel_task21single_purpose_kernel() #{{[0-9]+}} {
 // CHECK-HOST-LINUX-NEXT: entry:
 // CHECK-HOST-LINUX-NEXT:   %kernelFunc = alloca %struct.single_purpose_kernel, align 1
@@ -83,6 +92,13 @@ int main() {
 // CHECK-HOST-LINUX-NEXT:   ret void
 // CHECK-HOST-LINUX-NEXT: }
 //
+// CHECK-HOST-LINUX:      define internal void @"_Z18kernel_single_taskI6\CE\B4\CF\84\CF\87Z4mainEUliE_EvT0_"() #{{[0-9]+}} {
+// CHECK-HOST-LINUX-NEXT: entry:
+// CHECK-HOST-LINUX-NEXT:   %kernelFunc = alloca %class.anon.0, align 1
+// CHECK-HOST-LINUX-NEXT:   store ptr @.str.2, ptr @kernel_name, align 8
+// CHECK-HOST-LINUX-NEXT:   ret void
+// CHECK-HOST-LINUX-NEXT: }
+//
 // CHECK-HOST-WINDOWS:      define dso_local void @"?single_purpose_kernel_task@@YAXUsingle_purpose_kernel@@@Z"(i8 %kernelFunc.coerce) #{{[0-9]+}} {
 // CHECK-HOST-WINDOWS-NEXT: entry:
 // CHECK-HOST-WINDOWS-NEXT:   %kernelFunc = alloca %struct.single_purpose_kernel, align 1
@@ -100,6 +116,15 @@ int main() {
 // CHECK-HOST-WINDOWS-NEXT:   store ptr @"??_C at _0BC@NHCDOLAA at _ZTSZ4mainEUlT_E_?$AA@", ptr @"?kernel_name@?0???$kernel_single_task at V<lambda_1>@?0??main@@9 at V1?0??2 at 9@@@YAXV<lambda_1>@?0??main@@9@@Z at 3PEBDEB", align 8
 // CHECK-HOST-WINDOWS-NEXT:   ret void
 // CHECK-HOST-WINDOWS-NEXT: }
+//
+// CHECK-HOST-WINDOWS:      define internal void @"??$kernel_single_task at U\CE\B4\CF\84\CF\87@@V<lambda_2>@?0??main@@9@@@YAXV<lambda_2>@?0??main@@9@@Z"(i8 %kernelFunc.coerce) #{{[0-9]+}} {
+// CHECK-HOST-WINDOWS-NEXT: entry:
+// CHECK-HOST-WINDOWS-NEXT:   %kernelFunc = alloca %class.anon.0, align 1
+// CHECK-HOST-WINDOWS-NEXT:   %coerce.dive = getelementptr inbounds nuw %class.anon.0, ptr %kernelFunc, i32 0, i32 0
+// CHECK-HOST-WINDOWS-NEXT:   store i8 %kernelFunc.coerce, ptr %coerce.dive, align 1
+// CHECK-HOST-WINDOWS-NEXT:   store ptr @"??_C at _0M@BCGAEMBE at _ZTS6?N?$LE?O?$IE?O?$IH?$AA@", ptr @"?kernel_name@?0???$kernel_single_task at U\CE\B4\CF\84\CF\87@@V<lambda_2>@?0??main@@9@@@YAXV<lambda_2>@?0??main@@9@@Z at 3PEBDEB", align 8
+// CHECK-HOST-WINDOWS-NEXT:   ret void
+// CHECK-HOST-WINDOWS-NEXT: }
 
 // Verify that SYCL kernel caller functions are emitted for each device target.
 //
@@ -182,6 +207,44 @@ int main() {
 // CHECK-SPIR-NEXT:   }
 // CHECK-SPIR:        define internal spir_func void @_ZZ4mainENKUlT_E_clIiEEDaS_
 
+// IR for the SYCL kernel caller function generated for kernel_single_task with
+// the Delta Tau Chi type as the SYCL kernel name type.
+//
+// CHECK-AMDGCN:      Function Attrs: convergent mustprogress noinline norecurse nounwind optnone
+// CHECK-AMDGCN-NEXT: define dso_local amdgpu_kernel void @"_ZTS6\CE\B4\CF\84\CF\87"
+// CHECK-AMDGCN-SAME:   (ptr addrspace(4) noundef byref(%class.anon.0) align 1 %0) #[[AMDGCN_ATTR0]] {
+// CHECK-AMDGCN-NEXT: entry:
+// CHECK-AMDGCN-NEXT:   %coerce = alloca %class.anon.0, align 1, addrspace(5)
+// CHECK-AMDGCN-NEXT:   %kernelFunc = addrspacecast ptr addrspace(5) %coerce to ptr
+// CHECK-AMDGCN-NEXT:   call void @llvm.memcpy.p0.p4.i64(ptr align 1 %kernelFunc, ptr addrspace(4) align 1 %0, i64 1, i1 false)
+// CHECK-AMDGCN-NEXT:   call void @_ZZ4mainENKUliE_clEi
+// CHECK-AMDGCN-SAME:     (ptr noundef nonnull align 1 dereferenceable(1) %kernelFunc, i32 noundef 42) #[[AMDGCN_ATTR1:[0-9]+]]
+// CHECK-AMDGCN-NEXT:   ret void
+// CHECK-AMDGCN-NEXT: }
+// CHECK-AMDGCN:      define internal void @_ZZ4mainENKUliE_clEi
+//
+// CHECK-NVPTX:       Function Attrs: convergent mustprogress noinline norecurse nounwind optnone
+// CHECK-NVPTX-NEXT:  define dso_local ptx_kernel void @"_ZTS6\CE\B4\CF\84\CF\87"
+// CHECK-NVPTX-SAME:    (ptr noundef byval(%class.anon.0) align 1 %kernelFunc) #[[NVPTX_ATTR0:[0-9]+]] {
+// CHECK-NVPTX-NEXT:  entry:
+// CHECK-NVPTX-NEXT:    call void @_ZZ4mainENKUliE_clEi
+// CHECK-NVPTX-SAME:      (ptr noundef nonnull align 1 dereferenceable(1) %kernelFunc, i32 noundef 42) #[[NVPTX_ATTR1:[0-9]+]]
+// CHECK-NVPTX-NEXT:    ret void
+// CHECK-NVPTX-NEXT:  }
+// CHECK-NVPTX:       define internal void @_ZZ4mainENKUliE_clEi
+//
+// CHECK-SPIR:        Function Attrs: convergent mustprogress noinline norecurse nounwind optnone
+// CHECK-SPIR-NEXT:   define {{[a-z_ ]*}}spir_kernel void @"_ZTS6\CE\B4\CF\84\CF\87"
+// CHECK-SPIR-SAME:     (ptr noundef byval(%class.anon.0) align 1 %kernelFunc) #[[SPIR_ATTR0:[0-9]+]] {
+// CHECK-SPIR-NEXT:   entry:
+// CHECK-SPIR-NEXT:     %kernelFunc.ascast = addrspacecast ptr %kernelFunc to ptr addrspace(4)
+// CHECK-SPIR-NEXT:     call spir_func void @_ZZ4mainENKUliE_clEi
+// CHECK-SPIR-SAME:       (ptr addrspace(4) noundef align 1 dereferenceable_or_null(1) %kernelFunc.ascast, i32 noundef 42) #[[SPIR_ATTR1:[0-9]+]]
+// CHECK-SPIR-NEXT:     ret void
+// CHECK-SPIR-NEXT:   }
+// CHECK-SPIR:        define internal spir_func void @_ZZ4mainENKUliE_clEi
+
+
 // CHECK-AMDGCN: #[[AMDGCN_ATTR0]] = { convergent mustprogress noinline norecurse nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" }
 // CHECK-AMDGCN: #[[AMDGCN_ATTR1]] = { convergent nounwind }
 //

>From 7ee01a26c909700539aa83dbf2deced9089baedf Mon Sep 17 00:00:00 2001
From: Mariya Podchishchaeva <mariya.podchishchaeva at intel.com>
Date: Mon, 29 Sep 2025 19:16:00 +0200
Subject: [PATCH 05/29] [SYCL-Upstreaming] Add support for host kernel launch
 stmt generation (#51)

* Add support for host kernel launch stmt generation

This adds generation of a call to sycl_enqueue_kernel_launch function
aka "launcher" function. The launcher function can be a memeber of a
class or a free function defined at namespace scope. The lookup is
performed from SKEP attributed function scope. Because unqualified
lookup requires Scope object present and it only exists during parsing
stage and already EOLed at the point where templates instantiated, I had
to move some parts of SYCLKernelCallStmt generation to earlier stages
and now TreeTransform knows how to process SYCLKernelCallStmt.
I also had to invent a new expression - UnresolvedSYCLKernelExpr which
represents a string containing kernel name of a kernel that doesn't
exist yet. This expression is supposed to be transformed to a
StringLiteral during template instantiation phase. It should never reach
AST consumers like CodeGen of constexpr evaluators. This still requires
more testing and FIXME cleanups, but since it evolved into a quite
complicated patch I'm pushing it for earlier feedback.

* Remove a fixme from SemaSYCL

* Do not crash if original body was invalid

* Add AST test for skep-attributed member

* Fix a warning

* Extend codegen test a bit

* Find and replace

UnresolvedSYCLKernelNameExpr -> UnresolvedSYCLKernelLaunchExpr

* Implement the thing

* One more find and replace

* I don't know how it looks like

* Find and replace again

* Switch to UnresolvedSYCLKernelEntryPointStmt

* Apply suggestions from code review

* Remove log.txt

* Implement visiting

* Add tests

* Apply suggestions from code review

Co-authored-by: Tom Honermann <tom at honermann.net>

* IdExpr -> KernelLaunchIdExpr

* Don't rely on compound

* UnresolvedSYCLKernelEntryPointStmt -> UnresolvedSYCLKernelCall

* Fix warnings

* Rename sycl_enqueue_kernel_launch -> sycl_kernel_launch

* Apply suggestions from code review

Co-authored-by: Tom Honermann <tom at honermann.net>

* Remove array decay

* Add windows run line to the sema test

---------

Co-authored-by: Tom Honermann <tom at honermann.net>
---
 clang/include/clang/AST/RecursiveASTVisitor.h |   7 +
 clang/include/clang/AST/StmtSYCL.h            |  53 +++++
 clang/include/clang/Basic/AttrDocs.td         |  14 +-
 .../clang/Basic/DiagnosticSemaKinds.td        |   9 +
 clang/include/clang/Basic/StmtNodes.td        |   1 +
 clang/include/clang/Sema/ScopeInfo.h          |   4 +
 clang/include/clang/Sema/SemaSYCL.h           |   6 +-
 .../include/clang/Serialization/ASTBitCodes.h |   3 +
 clang/lib/AST/ComputeDependence.cpp           |   1 +
 clang/lib/AST/StmtPrinter.cpp                 |   5 +
 clang/lib/AST/StmtProfile.cpp                 |   5 +
 clang/lib/CodeGen/CGStmt.cpp                  |   1 +
 clang/lib/Sema/SemaDecl.cpp                   |  33 ++-
 clang/lib/Sema/SemaExceptionSpec.cpp          |   3 +
 clang/lib/Sema/SemaSYCL.cpp                   | 173 ++++++++++-----
 clang/lib/Sema/TreeTransform.h                |  19 ++
 clang/lib/Serialization/ASTReaderStmt.cpp     |  12 +
 clang/lib/Serialization/ASTWriterStmt.cpp     |  10 +
 clang/lib/StaticAnalyzer/Core/ExprEngine.cpp  |   1 +
 clang/test/AST/ast-print-sycl-kernel-call.cpp |   2 +-
 .../ast-dump-sycl-kernel-call-stmt.cpp        | 209 ++++++++++++++----
 .../ast-dump-sycl-kernel-entry-point.cpp      |   3 +
 .../CodeGenSYCL/kernel-caller-entry-point.cpp |  91 +++++++-
 .../unique_stable_name_windows_diff.cpp       |   2 +
 .../test/SemaSYCL/sycl-host-kernel-launch.cpp | 199 +++++++++++++++++
 ...-kernel-entry-point-attr-appertainment.cpp |   4 +
 .../sycl-kernel-entry-point-attr-grammar.cpp  |   4 +
 ...el-entry-point-attr-kernel-name-module.cpp |   6 +-
 ...ernel-entry-point-attr-kernel-name-pch.cpp |   9 +-
 ...cl-kernel-entry-point-attr-kernel-name.cpp |   6 +
 .../sycl-kernel-entry-point-attr-sfinae.cpp   |   5 +
 .../sycl-kernel-entry-point-attr-this.cpp     |   5 +
 clang/tools/libclang/CXCursor.cpp             |   1 +
 33 files changed, 780 insertions(+), 126 deletions(-)
 create mode 100644 clang/test/SemaSYCL/sycl-host-kernel-launch.cpp

diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h
index 4ed15ea52e21a..76be5b64f7ec3 100644
--- a/clang/include/clang/AST/RecursiveASTVisitor.h
+++ b/clang/include/clang/AST/RecursiveASTVisitor.h
@@ -2995,6 +2995,13 @@ DEF_TRAVERSE_STMT(ParenListExpr, {})
 DEF_TRAVERSE_STMT(SYCLUniqueStableNameExpr, {
   TRY_TO(TraverseTypeLoc(S->getTypeSourceInfo()->getTypeLoc()));
 })
+DEF_TRAVERSE_STMT(UnresolvedSYCLKernelCallStmt, {
+  if (getDerived().shouldVisitImplicitCode()) {
+    TRY_TO(TraverseStmt(S->getOriginalStmt()));
+    TRY_TO(TraverseStmt(S->getKernelLaunchIdExpr()));
+    ShouldVisitChildren = false;
+  }
+})
 DEF_TRAVERSE_STMT(OpenACCAsteriskSizeExpr, {})
 DEF_TRAVERSE_STMT(PredefinedExpr, {})
 DEF_TRAVERSE_STMT(ShuffleVectorExpr, {})
diff --git a/clang/include/clang/AST/StmtSYCL.h b/clang/include/clang/AST/StmtSYCL.h
index 70d8137992110..c8da4987321a9 100644
--- a/clang/include/clang/AST/StmtSYCL.h
+++ b/clang/include/clang/AST/StmtSYCL.h
@@ -99,6 +99,59 @@ class SYCLKernelCallStmt : public Stmt {
   }
 };
 
+// UnresolvedSYCLKernelCallStmt represents an invocation of a SYCL kernel in
+// a dependent context for which lookup of the sycl_enqueue_kernel_launch
+// identifier cannot be performed. These statements are transformed to
+// SYCLKernelCallStmt during template instantiation.
+class UnresolvedSYCLKernelCallStmt : public Stmt {
+  friend class ASTStmtReader;
+  Stmt *OriginalStmt = nullptr;
+  // KernelLaunchIdExpr stores an UnresolvedLookupExpr or UnresolvedMemberExpr
+  // corresponding to the SYCL kernel launch function for which a call
+  // will be synthesized during template instantiation.
+  Expr *KernelLaunchIdExpr = nullptr;
+  UnresolvedSYCLKernelCallStmt(CompoundStmt *CS, Expr *IdExpr)
+      : Stmt(UnresolvedSYCLKernelCallStmtClass), OriginalStmt(CS),
+        KernelLaunchIdExpr(IdExpr) {}
+
+  void setKernelLaunchIdExpr(Expr *IdExpr) { KernelLaunchIdExpr = IdExpr; }
+  void setOriginalStmt(CompoundStmt *CS) { OriginalStmt = CS; }
+
+public:
+  static UnresolvedSYCLKernelCallStmt *
+  Create(const ASTContext &C, CompoundStmt *CS, Expr *IdExpr) {
+    return new (C) UnresolvedSYCLKernelCallStmt(CS, IdExpr);
+  }
+
+  static UnresolvedSYCLKernelCallStmt *CreateEmpty(const ASTContext &C) {
+    return new (C) UnresolvedSYCLKernelCallStmt(nullptr, nullptr);
+  }
+
+  Expr *getKernelLaunchIdExpr() const { return KernelLaunchIdExpr; }
+  CompoundStmt *getOriginalStmt() { return cast<CompoundStmt>(OriginalStmt); }
+  const CompoundStmt *getOriginalStmt() const {
+    return cast<CompoundStmt>(OriginalStmt);
+  }
+
+  SourceLocation getBeginLoc() const LLVM_READONLY {
+    return getOriginalStmt()->getBeginLoc();
+  }
+
+  SourceLocation getEndLoc() const LLVM_READONLY {
+    return getOriginalStmt()->getEndLoc();
+  }
+  static bool classof(const Stmt *T) {
+    return T->getStmtClass() == UnresolvedSYCLKernelCallStmtClass;
+  }
+  child_range children() {
+    return child_range(&OriginalStmt, &OriginalStmt + 1);
+  }
+
+  const_child_range children() const {
+    return const_child_range(&OriginalStmt, &OriginalStmt + 1);
+  }
+};
+
 } // end namespace clang
 
 #endif // LLVM_CLANG_AST_STMTSYCL_H
diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td
index e3948df7e3598..0ea8bc9e07d01 100644
--- a/clang/include/clang/Basic/AttrDocs.td
+++ b/clang/include/clang/Basic/AttrDocs.td
@@ -566,7 +566,7 @@ follows.
   namespace sycl {
   class handler {
     template<typename KernelNameType, typename... Ts>
-    void sycl_enqueue_kernel_launch(const char *KernelName, Ts...) {
+    void sycl_kernel_launch(const char *KernelName, Ts...) {
       // Call functions appropriate for the desired offload backend
       // (OpenCL, CUDA, HIP, Level Zero, etc...) to enqueue kernel invocation.
     }
@@ -634,7 +634,7 @@ The offload kernel entry point for a SYCL kernel performs the following tasks:
 The ``sycl_kernel_entry_point`` attribute facilitates or automates these tasks
 by generating the offload kernel entry point, generating a unique symbol name
 for it, synthesizing code for kernel argument decomposition and reconstruction,
-and synthesizing a call to a ``sycl_enqueue_kernel_launch`` function template
+and synthesizing a call to a ``sycl_kernel_launch`` function template
 with the kernel name type, kernel symbol name, and (decomposed) kernel arguments
 passed as template or function arguments.
 
@@ -702,7 +702,7 @@ replaced with synthesized code that looks approximately as follows.
 
   sycl::stream sout = Kernel.sout;
   S s = Kernel.s;
-  sycl_enqueue_kernel_launch<KN>("kernel-symbol-name", sout, s);
+  sycl_kernel_launch<KN>("kernel-symbol-name", sout, s);
 
 There are a few items worthy of note:
 
@@ -713,16 +713,16 @@ There are a few items worthy of note:
 #. ``kernel-symbol-name`` is substituted for the actual symbol name that would
    be generated; these names are implementation details subject to change.
 
-#. Lookup for the ``sycl_enqueue_kernel_launch()`` function template is
+#. Lookup for the ``sycl_kernel_launch()`` function template is
    performed from the (possibly instantiated) location of the definition of
    ``kernel_entry_point()``. If overload resolution fails, the program is
    ill-formed. If the selected overload is a non-static member function, then
    ``this`` is passed for the implicit object parameter.
 
-#. Function arguments passed to ``sycl_enqueue_kernel_launch()`` are passed
+#. Function arguments passed to ``sycl_kernel_launch()`` are passed
    as if by ``std::forward<X>(x)``.
 
-#. The ``sycl_enqueue_kernel_launch()`` function is expected to be provided by
+#. The ``sycl_kernel_launch()`` function is expected to be provided by
    the SYCL library implementation. It is responsible for scheduling execution
    of the generated offload kernel entry point identified by
    ``kernel-symbol-name`` and copying the (decomposed) kernel arguments to
@@ -733,7 +733,7 @@ attribute to be called for the offload kernel entry point to be emitted. For
 inline functions and function templates, any ODR-use will suffice. For other
 functions, an ODR-use is not required; the offload kernel entry point will be
 emitted if the function is defined. In any case, a call to the function is
-required for the synthesized call to ``sycl_enqueue_kernel_launch()`` to occur.
+required for the synthesized call to ``sycl_kernel_launch()`` to occur.
 
 Functions declared with the ``sycl_kernel_entry_point`` attribute are not
 limited to the simple example shown above. They may have additional template
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 78e33ab1031e5..8771cffd0d03b 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -13283,6 +13283,15 @@ def err_sycl_entry_point_return_type : Error<
 def err_sycl_entry_point_deduced_return_type : Error<
   "the %0 attribute only applies to functions with a non-deduced 'void' return"
   " type">;
+def err_sycl_host_no_launch_function : Error<
+  "unable to find suitable 'sycl_kernel_launch' function for host code "
+  "synthesis">;
+def warn_sycl_device_no_host_launch_function : Warning<
+  "unable to find suitable 'sycl_kernel_launch' function for host code "
+  "synthesis">,
+  InGroup<DiagGroup<"sycl-host-launcher">>;
+def note_sycl_host_launch_function : Note<
+  "define 'sycl_kernel_launch' function template to fix this problem">;
 
 def warn_cuda_maxclusterrank_sm_90 : Warning<
   "maxclusterrank requires sm_90 or higher, CUDA arch provided: %0, ignoring "
diff --git a/clang/include/clang/Basic/StmtNodes.td b/clang/include/clang/Basic/StmtNodes.td
index cb869cc210627..b196382025c95 100644
--- a/clang/include/clang/Basic/StmtNodes.td
+++ b/clang/include/clang/Basic/StmtNodes.td
@@ -24,6 +24,7 @@ def CaseStmt : StmtNode<SwitchCase>;
 def DefaultStmt : StmtNode<SwitchCase>;
 def CapturedStmt : StmtNode<Stmt>;
 def SYCLKernelCallStmt : StmtNode<Stmt>;
+def UnresolvedSYCLKernelCallStmt : StmtNode<Stmt>;
 
 // Break/continue.
 def LoopControlStmt : StmtNode<Stmt, 1>;
diff --git a/clang/include/clang/Sema/ScopeInfo.h b/clang/include/clang/Sema/ScopeInfo.h
index 4f4d38c961140..f334f58ebd0a7 100644
--- a/clang/include/clang/Sema/ScopeInfo.h
+++ b/clang/include/clang/Sema/ScopeInfo.h
@@ -245,6 +245,10 @@ class FunctionScopeInfo {
   /// The set of GNU address of label extension "&&label".
   llvm::SmallVector<AddrLabelExpr *, 4> AddrLabels;
 
+  /// An unresolved identifier lookup expression for an implicit call
+  /// to a SYCL kernel launch function in a dependent context.
+  Expr *SYCLKernelLaunchIdExpr = nullptr;
+
 public:
   /// Represents a simple identification of a weak object.
   ///
diff --git a/clang/include/clang/Sema/SemaSYCL.h b/clang/include/clang/Sema/SemaSYCL.h
index 7ae556da2bec1..76046b765c0d6 100644
--- a/clang/include/clang/Sema/SemaSYCL.h
+++ b/clang/include/clang/Sema/SemaSYCL.h
@@ -66,7 +66,11 @@ class SemaSYCL : public SemaBase {
 
   void CheckSYCLExternalFunctionDecl(FunctionDecl *FD);
   void CheckSYCLEntryPointFunctionDecl(FunctionDecl *FD);
-  StmtResult BuildSYCLKernelCallStmt(FunctionDecl *FD, CompoundStmt *Body);
+  StmtResult BuildSYCLKernelCallStmt(FunctionDecl *FD, CompoundStmt *Body,
+                                     Expr *LaunchIdExpr);
+  ExprResult BuildSYCLKernelLaunchIdExpr(FunctionDecl *FD, QualType KNT);
+  StmtResult BuildUnresolvedSYCLKernelCallStmt(CompoundStmt *CS,
+                                                     Expr *IdExpr);
 };
 
 } // namespace clang
diff --git a/clang/include/clang/Serialization/ASTBitCodes.h b/clang/include/clang/Serialization/ASTBitCodes.h
index d72f1f9db86b2..08f6f21c7246f 100644
--- a/clang/include/clang/Serialization/ASTBitCodes.h
+++ b/clang/include/clang/Serialization/ASTBitCodes.h
@@ -1618,6 +1618,9 @@ enum StmtCode {
   /// A SYCLKernelCallStmt record.
   STMT_SYCLKERNELCALL,
 
+  /// A SYCLKernelCallStmt record.
+  STMT_UNRESOLVED_SYCL_KERNEL_CALL,
+
   /// A GCC-style AsmStmt record.
   STMT_GCCASM,
 
diff --git a/clang/lib/AST/ComputeDependence.cpp b/clang/lib/AST/ComputeDependence.cpp
index 34167eee8d8f2..66fe5646b1864 100644
--- a/clang/lib/AST/ComputeDependence.cpp
+++ b/clang/lib/AST/ComputeDependence.cpp
@@ -16,6 +16,7 @@
 #include "clang/AST/ExprConcepts.h"
 #include "clang/AST/ExprObjC.h"
 #include "clang/AST/ExprOpenMP.h"
+#include "clang/AST/StmtSYCL.h"
 #include "clang/Basic/ExceptionSpecificationType.h"
 #include "llvm/ADT/ArrayRef.h"
 
diff --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp
index 99b4f8ae5871b..4d364fdcd5502 100644
--- a/clang/lib/AST/StmtPrinter.cpp
+++ b/clang/lib/AST/StmtPrinter.cpp
@@ -1447,6 +1447,11 @@ void StmtPrinter::VisitSYCLUniqueStableNameExpr(
   OS << ")";
 }
 
+void StmtPrinter::VisitUnresolvedSYCLKernelCallStmt(
+    UnresolvedSYCLKernelCallStmt *Node) {
+  PrintStmt(Node->getOriginalStmt());
+}
+
 void StmtPrinter::VisitPredefinedExpr(PredefinedExpr *Node) {
   OS << PredefinedExpr::getIdentKindName(Node->getIdentKind());
 }
diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp
index 623905188b2dd..dc7fd352a67b2 100644
--- a/clang/lib/AST/StmtProfile.cpp
+++ b/clang/lib/AST/StmtProfile.cpp
@@ -1410,6 +1410,11 @@ void StmtProfiler::VisitSYCLUniqueStableNameExpr(
   VisitType(S->getTypeSourceInfo()->getType());
 }
 
+void StmtProfiler::VisitUnresolvedSYCLKernelCallStmt(
+    const UnresolvedSYCLKernelCallStmt *S) {
+  VisitStmt(S);
+}
+
 void StmtProfiler::VisitPredefinedExpr(const PredefinedExpr *S) {
   VisitExpr(S);
   ID.AddInteger(llvm::to_underlying(S->getIdentKind()));
diff --git a/clang/lib/CodeGen/CGStmt.cpp b/clang/lib/CodeGen/CGStmt.cpp
index 9a8e84a6cc12a..7b79e54132be8 100644
--- a/clang/lib/CodeGen/CGStmt.cpp
+++ b/clang/lib/CodeGen/CGStmt.cpp
@@ -114,6 +114,7 @@ void CodeGenFunction::EmitStmt(const Stmt *S, ArrayRef<const Attr *> Attrs) {
   case Stmt::DeferStmtClass:
   case Stmt::SEHLeaveStmtClass:
   case Stmt::SYCLKernelCallStmtClass:
+  case Stmt::UnresolvedSYCLKernelCallStmtClass:
     llvm_unreachable("should have emitted these statements as simple");
 
 #define STMT(Type, Base)
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 7af6ce62d08dd..6c088280fefde 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -15931,7 +15931,6 @@ Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Declarator &D,
   if (!Bases.empty())
     OpenMP().ActOnFinishedFunctionDefinitionInOpenMPDeclareVariantScope(Dcl,
                                                                         Bases);
-
   return Dcl;
 }
 
@@ -16352,6 +16351,20 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D,
 
   maybeAddDeclWithEffects(FD);
 
+  if (FD && !FD->isInvalidDecl() &&
+      FD->hasAttr<SYCLKernelEntryPointAttr>() && FnBodyScope) {
+    // Building KernelLaunchIdExpr requires performing an unqualified lookup
+    // which can only be done correctly while the stack of parsing scopes is
+    // alive, so we do it here when we start parsing function body even if it is
+    // a templated function.
+    const auto *SKEPAttr = FD->getAttr<SYCLKernelEntryPointAttr>();
+    if (!SKEPAttr->isInvalidAttr()) {
+      ExprResult LaunchIdExpr =
+          SYCL().BuildSYCLKernelLaunchIdExpr(FD, SKEPAttr->getKernelName());
+      getCurFunction()->SYCLKernelLaunchIdExpr = LaunchIdExpr.get();
+    }
+  }
+
   return D;
 }
 
@@ -16553,9 +16566,21 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, bool IsInstantiation,
       SKEPAttr->setInvalidAttr();
     }
 
-    if (Body && !FD->isTemplated() && !SKEPAttr->isInvalidAttr()) {
-      StmtResult SR =
-          SYCL().BuildSYCLKernelCallStmt(FD, cast<CompoundStmt>(Body));
+    // We don't need to build SYCLKernelCallStmt for template instantiations
+    // since it was already created by template instantiator.
+    if (Body && !SKEPAttr->isInvalidAttr()) {
+      StmtResult SR;
+      if (FD->isTemplated()) {
+        SR = SYCL().BuildUnresolvedSYCLKernelCallStmt(
+            cast<CompoundStmt>(Body), getCurFunction()->SYCLKernelLaunchIdExpr);
+      } else if (FD->isTemplateInstantiation()) {
+        assert(isa<SYCLKernelCallStmt>(Body));
+        SR = Body;
+      } else {
+        SR = SYCL().BuildSYCLKernelCallStmt(
+            FD, cast<CompoundStmt>(Body),
+            getCurFunction()->SYCLKernelLaunchIdExpr);
+      }
       if (SR.isInvalid())
         return nullptr;
       Body = SR.get();
diff --git a/clang/lib/Sema/SemaExceptionSpec.cpp b/clang/lib/Sema/SemaExceptionSpec.cpp
index b996dfb405b16..56079ea8e1bf8 100644
--- a/clang/lib/Sema/SemaExceptionSpec.cpp
+++ b/clang/lib/Sema/SemaExceptionSpec.cpp
@@ -1260,6 +1260,9 @@ CanThrowResult Sema::canThrow(const Stmt *S) {
     return canSubStmtsThrow(*this, SKCS->getKernelLaunchStmt());
   }
 
+  case Stmt::UnresolvedSYCLKernelCallStmtClass:
+    return CT_Dependent;
+
     // ObjC message sends are like function calls, but never have exception
     // specs.
   case Expr::ObjCMessageExprClass:
diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp
index a6473e14fd604..12512b5d65113 100644
--- a/clang/lib/Sema/SemaSYCL.cpp
+++ b/clang/lib/Sema/SemaSYCL.cpp
@@ -390,53 +390,23 @@ void SemaSYCL::CheckSYCLEntryPointFunctionDecl(FunctionDecl *FD) {
   }
 }
 
-namespace {
+ExprResult SemaSYCL::BuildSYCLKernelLaunchIdExpr(FunctionDecl *FD,
+                                                 QualType KNT) {
 
-CompoundStmt *BuildSYCLKernelLaunchStmt(Sema &SemaRef, FunctionDecl *FD,
-                                        const std::string &KernelName) {
   ASTContext &Ctx = SemaRef.getASTContext();
-  SmallVector<Stmt *> Stmts;
+  // Some routines need a valid source location to work correctly.
+  SourceLocation BodyLoc =
+      FD->getEndLoc().isValid() ? FD->getEndLoc() : FD->getLocation();
 
-  // Prepare a string literal that contains the kernel name.
-  QualType KernelNameCharTy = Ctx.CharTy.withConst();
-  llvm::APInt KernelNameSize(Ctx.getTypeSize(Ctx.getSizeType()),
-                             KernelName.size() + 1);
-  QualType KernelNameArrayTy = Ctx.getConstantArrayType(
-      KernelNameCharTy, KernelNameSize, nullptr, ArraySizeModifier::Normal, 0);
-  StringLiteral *KernelNameExpr = StringLiteral::Create(
-      Ctx, KernelName, StringLiteralKind::Ordinary,
-      /*Pascal*/ false, KernelNameArrayTy, SourceLocation());
-
-  // FIXME: An extern variable declaration with assignment to the kernel
-  // name expression is added to Stmts as a temporary measure to see results.
-  // reflected in tests. The kernel name expression will need to be passed as
-  // the first function argument in a call to sycl_enqueue_kernel_launch.
-  QualType ExternVarType = Ctx.getPointerType(Ctx.CharTy.withConst());
-  const IdentifierInfo *ExternVarName =
-      SemaRef.getPreprocessor().getIdentifierInfo("kernel_name");
-  VarDecl *ExternVarDecl = VarDecl::Create(
-      Ctx, FD, SourceLocation(), SourceLocation(), ExternVarName, ExternVarType,
-      /*TInfo*/ nullptr, SC_Extern);
-  DeclStmt *ExternVarDeclStmt = new (Ctx)
-      DeclStmt(DeclGroupRef(ExternVarDecl), SourceLocation(), SourceLocation());
-  Stmts.push_back(ExternVarDeclStmt);
-  DeclRefExpr *ExternVarDeclRef = new (Ctx) DeclRefExpr(
-      Ctx, ExternVarDecl, /*RefersToEnclosingVariableOrCapture*/ false,
-      ExternVarType, VK_LValue, SourceLocation());
-  ImplicitCastExpr *KernelNameArrayDecayExpr = new (Ctx) ImplicitCastExpr(
-      ImplicitCastExpr::OnStack, ExternVarType, CK_ArrayToPointerDecay,
-      KernelNameExpr, VK_PRValue, FPOptionsOverride());
-  BinaryOperator *AssignmentExpr = BinaryOperator::Create(
-      Ctx, ExternVarDeclRef, KernelNameArrayDecayExpr, BO_Assign, ExternVarType,
-      VK_LValue, OK_Ordinary, SourceLocation(), FPOptionsOverride());
-  Stmts.push_back(AssignmentExpr);
+  IdentifierInfo &LaunchFooName =
+      Ctx.Idents.get("sycl_kernel_launch", tok::TokenKind::identifier);
 
   // Perform overload resolution for a call to an accessible (member) function
-  // template named 'sycl_enqueue_kernel_launch' from within the definition of
-  // FD where:
+  // template named 'sycl_kernel_launch' "from within the definition of
+  // FD where":
   // - The kernel name type is passed as the first template argument.
-  // - Any remaining template parameters are deduced from the function arguments
-  //   or assigned by default template arguments.
+  // - Any remaining template parameters are deduced from the function
+  //   arguments or assigned by default template arguments.
   // - 'this' is passed as the implicit function argument if 'FD' is a
   //   non-static member function.
   // - The name of the kernel, expressed as a string literal, is passed as the
@@ -444,10 +414,108 @@ CompoundStmt *BuildSYCLKernelLaunchStmt(Sema &SemaRef, FunctionDecl *FD,
   // - The parameters of FD are forwarded as-if by 'std::forward()' as the
   //   remaining explicit function arguments.
   // - Any remaining function arguments are initialized by default arguments.
-  CompoundStmt *LaunchStmt = CompoundStmt::Create(
-      Ctx, Stmts, FPOptionsOverride(), SourceLocation(), SourceLocation());
+  LookupResult Result(SemaRef, &LaunchFooName, BodyLoc,
+                      Sema::LookupOrdinaryName);
+  CXXScopeSpec SS;
+  SemaRef.LookupTemplateName(Result, SemaRef.getCurScope(), SS,
+                             /*ObjectType=*/QualType(),
+                             /*EnteringContext=*/false, BodyLoc);
+
+  if (Result.empty() || Result.isAmbiguous()) {
+    SemaRef.Diag(BodyLoc, SemaRef.getLangOpts().SYCLIsHost
+                              ? diag::err_sycl_host_no_launch_function
+                              : diag::warn_sycl_device_no_host_launch_function);
+    SemaRef.Diag(BodyLoc, diag::note_sycl_host_launch_function);
+
+    return ExprError();
+  }
+
+  TemplateArgumentListInfo TALI{BodyLoc, BodyLoc};
+  TemplateArgument KNTA = TemplateArgument(KNT);
+  TemplateArgumentLoc TAL =
+      SemaRef.getTrivialTemplateArgumentLoc(KNTA, QualType(), BodyLoc);
+  TALI.addArgument(TAL);
+  ExprResult IdExpr;
+  if (SemaRef.isPotentialImplicitMemberAccess(SS, Result,
+                                              /*IsAddressOfOperand=*/false))
+    // BuildPossibleImplicitMemberExpr creates UnresolvedMemberExpr. Using it
+    // allows to pass implicit/explicit this argument automatically.
+    IdExpr = SemaRef.BuildPossibleImplicitMemberExpr(SS, BodyLoc, Result, &TALI,
+                                                     SemaRef.getCurScope());
+  else
+    IdExpr = SemaRef.BuildTemplateIdExpr(SS, BodyLoc, Result,
+                                         /*RequiresADL=*/true, &TALI);
+
+  // Can happen if SKEP attributed function is a static member, but the launcher
+  // is a regular member. Perhaps emit a note saying that we're in host code
+  // synthesis.
+  if (IdExpr.isInvalid())
+    return ExprError();
+
+  return IdExpr;
+}
 
-  return LaunchStmt;
+StmtResult SemaSYCL::BuildUnresolvedSYCLKernelCallStmt(CompoundStmt *CS,
+                                                             Expr *IdExpr) {
+  return UnresolvedSYCLKernelCallStmt::Create(SemaRef.getASTContext(), CS,
+                                                    IdExpr);
+}
+
+namespace {
+
+void PrepareKernelArgumentsForKernelLaunch(SmallVectorImpl<Expr *> &Args,
+                                                  const SYCLKernelInfo *SKI,
+                                                  Sema &SemaRef,
+                                                  SourceLocation Loc) {
+  assert(SKI && "Need a kernel!");
+  ASTContext &Ctx = SemaRef.getASTContext();
+
+  // Prepare a string literal that contains the kernel name.
+  const std::string KernelName = SKI->GetKernelName();
+  QualType KernelNameCharTy = Ctx.CharTy.withConst();
+  llvm::APInt KernelNameSize(Ctx.getTypeSize(Ctx.getSizeType()),
+                             KernelName.size() + 1);
+  QualType KernelNameArrayTy = Ctx.getConstantArrayType(
+      KernelNameCharTy, KernelNameSize, nullptr, ArraySizeModifier::Normal, 0);
+  Expr *KernelNameExpr =
+      StringLiteral::Create(Ctx, KernelName, StringLiteralKind::Ordinary,
+                            /*Pascal*/ false, KernelNameArrayTy, Loc);
+  Args.push_back(KernelNameExpr);
+
+  // Right now we simply forward the arguments of the skep-attributed function.
+  // With decomposition present there can be another logic.
+  // Make sure to use CurContext to avoid diagnostics that we're using a
+  // variable coming from another context. The function should be the same as in
+  // the kernel info though.
+  auto *FD = cast<FunctionDecl>(SemaRef.CurContext);
+  assert(declaresSameEntity(FD, SKI->getKernelEntryPointDecl()));
+  for (ParmVarDecl *PVD : FD->parameters()) {
+    QualType ParamType = PVD->getOriginalType().getNonReferenceType();
+    Expr *DRE = SemaRef.BuildDeclRefExpr(PVD, ParamType, VK_LValue, Loc);
+    assert(DRE);
+    Args.push_back(DRE);
+  }
+}
+
+StmtResult BuildSYCLKernelLaunchStmt(Sema &SemaRef,
+                                            const SYCLKernelInfo *SKI,
+                                            Expr *IdExpr, SourceLocation Loc) {
+  SmallVector<Stmt *> Stmts;
+  assert(SKI && "Need a Kernel!");
+
+  if (IdExpr) {
+    llvm::SmallVector<Expr *, 12> Args;
+    PrepareKernelArgumentsForKernelLaunch(Args, SKI, SemaRef, Loc);
+    ExprResult LaunchResult =
+        SemaRef.BuildCallExpr(SemaRef.getCurScope(), IdExpr, Loc, Args, Loc);
+    if (LaunchResult.isInvalid())
+      return StmtError();
+
+    Stmts.push_back(LaunchResult.get());
+  }
+
+  return CompoundStmt::Create(SemaRef.getASTContext(), Stmts,
+                              FPOptionsOverride(), Loc, Loc);
 }
 
 // The body of a function declared with the [[sycl_kernel_entry_point]]
@@ -535,11 +603,11 @@ OutlinedFunctionDecl *BuildSYCLKernelEntryPointOutline(Sema &SemaRef,
 } // unnamed namespace
 
 StmtResult SemaSYCL::BuildSYCLKernelCallStmt(FunctionDecl *FD,
-                                             CompoundStmt *Body) {
+                                             CompoundStmt *Body,
+                                             Expr *LaunchIdExpr) {
   assert(!FD->isInvalidDecl());
   assert(!FD->isTemplated());
   assert(FD->hasPrototype());
-
   // The current context must be the function definition context to ensure
   // that name lookup and parameter and local variable creation are performed
   // within the correct scope.
@@ -557,18 +625,19 @@ StmtResult SemaSYCL::BuildSYCLKernelCallStmt(FunctionDecl *FD,
   assert(declaresSameEntity(SKI.getKernelEntryPointDecl(), FD) &&
          "SYCL kernel name conflict");
 
-  // Build the kernel launch statement.
-  Stmt *LaunchStmt =
-      BuildSYCLKernelLaunchStmt(SemaRef, FD, SKI.GetKernelName());
-  assert(LaunchStmt);
-
   // Build the outline of the synthesized device entry point function.
   OutlinedFunctionDecl *OFD =
       BuildSYCLKernelEntryPointOutline(SemaRef, FD, Body);
   assert(OFD);
 
+  // Build host kernel launch stmt.
+  SourceLocation BodyLoc =
+      FD->getEndLoc().isValid() ? FD->getEndLoc() : FD->getLocation();
+  StmtResult LaunchRes =
+      BuildSYCLKernelLaunchStmt(SemaRef, &SKI, LaunchIdExpr, BodyLoc);
+
   Stmt *NewBody =
-      new (getASTContext()) SYCLKernelCallStmt(Body, LaunchStmt, OFD);
+      new (getASTContext()) SYCLKernelCallStmt(Body, LaunchRes.get(), OFD);
 
   return NewBody;
 }
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 6a4d88b28c614..671f5440d36cf 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -13055,6 +13055,25 @@ ExprResult TreeTransform<Derived>::TransformSYCLUniqueStableNameExpr(
       E->getLocation(), E->getLParenLocation(), E->getRParenLocation(), NewT);
 }
 
+template <typename Derived>
+StmtResult TreeTransform<Derived>::TransformUnresolvedSYCLKernelCallStmt(
+    UnresolvedSYCLKernelCallStmt *S) {
+  ExprResult IdExpr = getDerived().TransformExpr(S->getKernelLaunchIdExpr());
+
+  if (IdExpr.isInvalid())
+     return StmtError();
+
+  StmtResult Body = getDerived().TransformStmt(S->getOriginalStmt());
+  if (Body.isInvalid())
+     return StmtError();
+
+  StmtResult SR = SemaRef.SYCL().BuildSYCLKernelCallStmt(
+      cast<FunctionDecl>(SemaRef.CurContext), cast<CompoundStmt>(Body.get()),
+      IdExpr.get());
+
+  return SR;
+}
+
 template <typename Derived>
 ExprResult TreeTransform<Derived>::TransformCXXReflectExpr(CXXReflectExpr *E) {
   // TODO(reflection): Implement its transform
diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp
index 9e8619596f789..f351e185e5b58 100644
--- a/clang/lib/Serialization/ASTReaderStmt.cpp
+++ b/clang/lib/Serialization/ASTReaderStmt.cpp
@@ -609,6 +609,14 @@ void ASTStmtReader::VisitSYCLUniqueStableNameExpr(SYCLUniqueStableNameExpr *E) {
   E->setTypeSourceInfo(Record.readTypeSourceInfo());
 }
 
+void ASTStmtReader::VisitUnresolvedSYCLKernelCallStmt(
+    UnresolvedSYCLKernelCallStmt *S) {
+  VisitStmt(S);
+
+  S->setOriginalStmt(cast<CompoundStmt>(Record.readSubStmt()));
+  S->setKernelLaunchIdExpr(Record.readExpr());
+}
+
 void ASTStmtReader::VisitPredefinedExpr(PredefinedExpr *E) {
   VisitExpr(E);
   bool HasFunctionName = Record.readInt();
@@ -3213,6 +3221,10 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
       S = SYCLUniqueStableNameExpr::CreateEmpty(Context);
       break;
 
+    case STMT_UNRESOLVED_SYCL_KERNEL_CALL:
+      S = UnresolvedSYCLKernelCallStmt::CreateEmpty(Context);
+      break;
+
     case EXPR_OPENACC_ASTERISK_SIZE:
       S = OpenACCAsteriskSizeExpr::CreateEmpty(Context);
       break;
diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp
index 2072bbfe8311c..d9b95e53f2da0 100644
--- a/clang/lib/Serialization/ASTWriterStmt.cpp
+++ b/clang/lib/Serialization/ASTWriterStmt.cpp
@@ -696,6 +696,16 @@ void ASTStmtWriter::VisitSYCLUniqueStableNameExpr(SYCLUniqueStableNameExpr *E) {
   Code = serialization::EXPR_SYCL_UNIQUE_STABLE_NAME;
 }
 
+void ASTStmtWriter::VisitUnresolvedSYCLKernelCallStmt(
+    UnresolvedSYCLKernelCallStmt *S) {
+  VisitStmt(S);
+
+  Record.AddStmt(S->getOriginalStmt());
+  Record.AddStmt(S->getKernelLaunchIdExpr());
+
+  Code = serialization::STMT_UNRESOLVED_SYCL_KERNEL_CALL;
+}
+
 void ASTStmtWriter::VisitPredefinedExpr(PredefinedExpr *E) {
   VisitExpr(E);
 
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
index 883c7b5d66c32..d74b58e297d7b 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -1832,6 +1832,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
     case Stmt::OMPTargetParallelGenericLoopDirectiveClass:
     case Stmt::CapturedStmtClass:
     case Stmt::SYCLKernelCallStmtClass:
+    case Stmt::UnresolvedSYCLKernelCallStmtClass:
     case Stmt::OpenACCComputeConstructClass:
     case Stmt::OpenACCLoopConstructClass:
     case Stmt::OpenACCCombinedConstructClass:
diff --git a/clang/test/AST/ast-print-sycl-kernel-call.cpp b/clang/test/AST/ast-print-sycl-kernel-call.cpp
index 2243ee024be1a..64c6624b768c9 100644
--- a/clang/test/AST/ast-print-sycl-kernel-call.cpp
+++ b/clang/test/AST/ast-print-sycl-kernel-call.cpp
@@ -3,7 +3,7 @@
 
 struct sycl_kernel_launcher {
   template<typename KernelName, typename... Ts>
-  void sycl_enqueue_kernel_launch(const char *, Ts...) {}
+  void sycl_kernel_launch(const char *, Ts...) {}
 
   template<typename KernelName, typename KernelType>
   void kernel_entry_point(KernelType kernel) {
diff --git a/clang/test/ASTSYCL/ast-dump-sycl-kernel-call-stmt.cpp b/clang/test/ASTSYCL/ast-dump-sycl-kernel-call-stmt.cpp
index cc26d1d195dde..d64db19c8304e 100644
--- a/clang/test/ASTSYCL/ast-dump-sycl-kernel-call-stmt.cpp
+++ b/clang/test/ASTSYCL/ast-dump-sycl-kernel-call-stmt.cpp
@@ -34,6 +34,8 @@ template<int> struct K {
   void operator()(Ts...) const {}
 };
 
+template <typename KernelName, typename... Ts>
+void sycl_kernel_launch(const char *, Ts...) {}
 
 [[clang::sycl_kernel_entry_point(KN<1>)]]
 void skep1() {
@@ -42,12 +44,11 @@ void skep1() {
 // CHECK-NEXT: | |-SYCLKernelCallStmt {{.*}}
 // CHECK-NEXT: | | |-CompoundStmt {{.*}}
 // CHECK-NEXT: | | |-CompoundStmt {{.*}}
-// CHECK-NEXT: | | | |-DeclStmt {{.*}}
-// CHECK-NEXT: | | | | `-VarDecl {{.*}} kernel_name 'const char *' extern
-// CHECK-NEXT: | | | `-BinaryOperator {{.*}} 'const char *' lvalue '='
-// CHECK-NEXT: | | |   |-DeclRefExpr {{.*}} 'const char *' lvalue Var {{.*}} 'kernel_name' 'const char *'
+// CHECK-NEXT: | | | `-CallExpr {{.*}}
+// CHECK-NEXT: | | |   |-ImplicitCastExpr {{.*}} 'void (*)(const char *)' <FunctionToPointerDecay>
+// CHECK-NEXT: | | |   | `-DeclRefExpr {{.*}} 'void (const char *)' lvalue Function {{.*}} 'sycl_kernel_launch' {{.*}}
 // CHECK-NEXT: | | |   `-ImplicitCastExpr {{.*}} 'const char *' <ArrayToPointerDecay>
-// CHECK-NEXT: | | |     `-StringLiteral {{.*}} 'const char[14]' lvalue "_ZTS2KNILi1EE"
+// CHECK-NEXT: | | |       `-StringLiteral {{.*}} 'const char[14]' lvalue "_ZTS2KNILi1EE"
 // CHECK-NEXT: | | `-OutlinedFunctionDecl {{.*}}
 // CHECK-NEXT: | |   `-CompoundStmt {{.*}}
 // CHECK-NEXT: | `-SYCLKernelEntryPointAttr {{.*}} KN<1>
@@ -64,9 +65,10 @@ void skep2<KN<2>>(K<2>);
 // CHECK-NEXT: | |-TemplateTypeParmDecl {{.*}} KT
 // CHECK-NEXT: | |-FunctionDecl {{.*}} skep2 'void (KT)'
 // CHECK-NEXT: | | |-ParmVarDecl {{.*}} k 'KT'
-// CHECK-NEXT: | | |-CompoundStmt {{.*}}
-// CHECK-NEXT: | | | `-CallExpr {{.*}} '<dependent type>'
-// CHECK-NEXT: | | |   `-DeclRefExpr {{.*}} 'KT' lvalue ParmVar {{.*}} 'k' 'KT'
+// CHECK-NEXT: | | |-UnresolvedSYCLKernelCallStmt {{.*}}
+// CHECK-NEXT: | | | `-CompoundStmt {{.*}}
+// CHECK-NEXT: | | |   `-CallExpr {{.*}} '<dependent type>'
+// CHECK-NEXT: | | |     `-DeclRefExpr {{.*}} 'KT' lvalue ParmVar {{.*}} 'k' 'KT'
 // CHECK-NEXT: | | `-SYCLKernelEntryPointAttr {{.*}} KNT
 
 // CHECK-NEXT: | `-FunctionDecl {{.*}} skep2 'void (K<2>)' explicit_instantiation_definition instantiated_from 0x{{.+}}
@@ -85,12 +87,14 @@ void skep2<KN<2>>(K<2>);
 // CHECK-NEXT: |   | |   `-ImplicitCastExpr {{.*}} 'const K<2>' lvalue <NoOp>
 // CHECK-NEXT: |   | |     `-DeclRefExpr {{.*}} 'K<2>' lvalue ParmVar {{.*}} 'k' 'K<2>'
 // CHECK-NEXT: |   | |-CompoundStmt {{.*}}
-// CHECK-NEXT: |   | | |-DeclStmt {{.*}}
-// CHECK-NEXT: |   | | | `-VarDecl {{.*}} kernel_name 'const char *' extern
-// CHECK-NEXT: |   | | `-BinaryOperator {{.*}} 'const char *' lvalue '='
-// CHECK-NEXT: |   | |   |-DeclRefExpr {{.*}} 'const char *' lvalue Var {{.*}} 'kernel_name' 'const char *'
-// CHECK-NEXT: |   | |   `-ImplicitCastExpr {{.*}} 'const char *' <ArrayToPointerDecay>
-// CHECK-NEXT: |   | |     `-StringLiteral {{.*}} 'const char[14]' lvalue "_ZTS2KNILi2EE"
+// CHECK-NEXT: |   | | `-CallExpr {{.*}} 'void'
+// CHECK-NEXT: |   | |   |-ImplicitCastExpr {{.*}} <FunctionToPointerDecay>
+// CHECK-NEXT: |   | |   | `-DeclRefExpr {{.*}} 'void (const char *, K<2>)' lvalue Function {{.*}} 'sycl_kernel_launch' {{.*}}
+// CHECK-NEXT: |   | |   |-ImplicitCastExpr {{.*}} 'const char *' <ArrayToPointerDecay>
+// CHECK-NEXT: |   | |   | `-StringLiteral {{.*}} 'const char[14]' lvalue "_ZTS2KNILi2EE"
+// CHECK-NEXT: |   | |   `-CXXConstructExpr {{.*}} 'K<2>' 'void (const K<2> &) noexcept'
+// CHECK-NEXT: |   | |     `-ImplicitCastExpr {{.*}} <NoOp>
+// CHECK-NEXT: |   | |       `-DeclRefExpr {{.*}} 'K<2>' lvalue ParmVar {{.*}} 'k' 'K<2>'
 // CHECK-NEXT: |   | `-OutlinedFunctionDecl {{.*}}
 // CHECK-NEXT: |   |   |-ImplicitParamDecl {{.*}} implicit used k 'K<2>'
 // CHECK-NEXT: |   |   `-CompoundStmt {{.*}}
@@ -116,9 +120,10 @@ void skep3<KN<3>>(K<3> k) {
 // CHECK-NEXT: | |-TemplateTypeParmDecl {{.*}} KT
 // CHECK-NEXT: | |-FunctionDecl {{.*}} skep3 'void (KT)'
 // CHECK-NEXT: | | |-ParmVarDecl {{.*}} k 'KT'
-// CHECK-NEXT: | | |-CompoundStmt {{.*}}
-// CHECK-NEXT: | | | `-CallExpr {{.*}} '<dependent type>'
-// CHECK-NEXT: | | |   `-DeclRefExpr {{.*}} 'KT' lvalue ParmVar {{.*}} 'k' 'KT'
+// CHECK-NEXT: | | |-UnresolvedSYCLKernelCallStmt {{.*}}
+// CHECK-NEXT: | | | `-CompoundStmt {{.*}}
+// CHECK-NEXT: | | |   `-CallExpr {{.*}} '<dependent type>'
+// CHECK-NEXT: | | |     `-DeclRefExpr {{.*}} 'KT' lvalue ParmVar {{.*}} 'k' 'KT'
 // CHECK-NEXT: | | `-SYCLKernelEntryPointAttr {{.*}} KNT
 
 // CHECK-NEXT: | `-Function {{.*}} 'skep3' 'void (K<3>)'
@@ -138,12 +143,14 @@ void skep3<KN<3>>(K<3> k) {
 // CHECK-NEXT: | | |   `-ImplicitCastExpr {{.*}} 'const K<3>' lvalue <NoOp>
 // CHECK-NEXT: | | |     `-DeclRefExpr {{.*}} 'K<3>' lvalue ParmVar {{.*}} 'k' 'K<3>'
 // CHECK-NEXT: | | |-CompoundStmt {{.*}}
-// CHECK-NEXT: | | | |-DeclStmt {{.*}}
-// CHECK-NEXT: | | | | `-VarDecl {{.*}} kernel_name 'const char *' extern
-// CHECK-NEXT: | | | `-BinaryOperator {{.*}} 'const char *' lvalue '='
-// CHECK-NEXT: | | |   |-DeclRefExpr {{.*}} 'const char *' lvalue Var {{.*}} 'kernel_name' 'const char *'
-// CHECK-NEXT: | | |   `-ImplicitCastExpr {{.*}} 'const char *' <ArrayToPointerDecay>
-// CHECK-NEXT: | | |     `-StringLiteral {{.*}} 'const char[14]' lvalue "_ZTS2KNILi3EE"
+// CHECK-NEXT: | | | `-CallExpr {{.*}}
+// CHECK-NEXT: | | |   |-ImplicitCastExpr {{.*}} 'void (*)(const char *, K<3>)' <FunctionToPointerDecay>
+// CHECK-NEXT: | | |   | `-DeclRefExpr {{.*}} 'void (const char *, K<3>)' lvalue Function {{.*}} 'sycl_kernel_launch' 'void (const char *, K<3>)' {{.*}}
+// CHECK-NEXT: | | |   |-ImplicitCastExpr {{.*}} 'const char *' <ArrayToPointerDecay>
+// CHECK-NEXT: | | |   | `-StringLiteral {{.*}} 'const char[14]' lvalue "_ZTS2KNILi3EE"
+// CHECK-NEXT: | | |   `-CXXConstructExpr {{.*}} 'K<3>' 'void (const K<3> &) noexcept'
+// CHECK-NEXT: | | |     `-ImplicitCastExpr {{.*}} 'const K<3>' lvalue <NoOp>
+// CHECK-NEXT: | | |       `-DeclRefExpr {{.*}} 'K<3>' lvalue ParmVar {{.*}} 'k' 'K<3>'
 // CHECK-NEXT: | | `-OutlinedFunctionDecl {{.*}}
 // CHECK-NEXT: | |   |-ImplicitParamDecl {{.*}} implicit used k 'K<3>'
 // CHECK-NEXT: | |   `-CompoundStmt {{.*}}
@@ -174,12 +181,18 @@ void skep4(K<4> k, int p1, int p2) {
 // CHECK-NEXT: | | |   `-ImplicitCastExpr {{.*}} 'int' <LValueToRValue>
 // CHECK-NEXT: | | |     `-DeclRefExpr {{.*}} 'int' lvalue ParmVar {{.*}} 'p2' 'int'
 // CHECK-NEXT: | | |-CompoundStmt {{.*}}
-// CHECK-NEXT: | | | |-DeclStmt {{.*}}
-// CHECK-NEXT: | | | | `-VarDecl {{.*}} kernel_name 'const char *' extern
-// CHECK-NEXT: | | | `-BinaryOperator {{.*}} 'const char *' lvalue '='
-// CHECK-NEXT: | | |   |-DeclRefExpr {{.*}} 'const char *' lvalue Var {{.*}} 'kernel_name' 'const char *'
-// CHECK-NEXT: | | |   `-ImplicitCastExpr {{.*}} 'const char *' <ArrayToPointerDecay>
-// CHECK-NEXT: | | |     `-StringLiteral {{.*}} 'const char[14]' lvalue "_ZTS2KNILi4EE"
+// CHECK-NEXT: | | | `-CallExpr {{.*}} 'void'
+// CHECK-NEXT: | | |   |-ImplicitCastExpr {{.*}} 'void (*)(const char *, K<4>, int, int)' <FunctionToPointerDecay>
+// CHECK-NEXT: | | |   | `-DeclRefExpr {{.*}} 'void (const char *, K<4>, int, int)' lvalue Function {{.*}} 'sycl_kernel_launch' 'void (const char *, K<4>, int, int)' {{.*}}
+// CHECK-NEXT: | | |   |-ImplicitCastExpr {{.*}} 'const char *' <ArrayToPointerDecay>
+// CHECK-NEXT: | | |   | `-StringLiteral {{.*}} 'const char[14]' lvalue "_ZTS2KNILi4EE"
+// CHECK-NEXT: | | |   |-CXXConstructExpr {{.*}} 'K<4>' 'void (const K<4> &) noexcept'
+// CHECK-NEXT: | | |   | `-ImplicitCastExpr {{.*}} 'const K<4>' lvalue <NoOp>
+// CHECK-NEXT: | | |   |   `-DeclRefExpr {{.*}} 'K<4>' lvalue ParmVar {{.*}} 'k' 'K<4>'
+// CHECK-NEXT: | | |   |-ImplicitCastExpr {{.*}} 'int' <LValueToRValue>
+// CHECK-NEXT: | | |   | `-DeclRefExpr {{.*}} 'int' lvalue ParmVar {{.*}} 'p1' 'int'
+// CHECK-NEXT: | | |   `-ImplicitCastExpr {{.*}} 'int' <LValueToRValue>
+// CHECK-NEXT: | | |     `-DeclRefExpr {{.*}} 'int' lvalue ParmVar {{.*}} 'p2' 'int'
 // CHECK-NEXT: | | `-OutlinedFunctionDecl {{.*}}
 // CHECK-NEXT: | |   |-ImplicitParamDecl {{.*}} implicit used k 'K<4>'
 // CHECK-NEXT: | |   |-ImplicitParamDecl {{.*}} implicit used p1 'int'
@@ -211,12 +224,22 @@ void skep5(int unused1, K<5> k, int unused2, int p, int unused3) {
 // CHECK-NEXT: | |-SYCLKernelCallStmt {{.*}}
 // CHECK-NEXT: | | |-CompoundStmt {{.*}}
 // CHECK:      | | |-CompoundStmt {{.*}}
-// CHECK-NEXT: | | | |-DeclStmt {{.*}}
-// CHECK-NEXT: | | | | `-VarDecl {{.*}} kernel_name 'const char *' extern
-// CHECK-NEXT: | | | `-BinaryOperator {{.*}} 'const char *' lvalue '='
-// CHECK-NEXT: | | |   |-DeclRefExpr {{.*}} 'const char *' lvalue Var {{.*}} 'kernel_name' 'const char *'
-// CHECK-NEXT: | | |   `-ImplicitCastExpr {{.*}} 'const char *' <ArrayToPointerDecay>
-// CHECK-NEXT: | | |     `-StringLiteral {{.*}} 'const char[14]' lvalue "_ZTS2KNILi5EE"
+// CHECK-NEXT: | | | `-CallExpr {{.*}} 'void'
+// CHECK-NEXT: | | |   |-ImplicitCastExpr {{.*}} 'void (*)(const char *, int, K<5>, int, int, int)' <FunctionToPointerDecay>
+// CHECK-NEXT: | | |   | `-DeclRefExpr {{.*}} 'void (const char *, int, K<5>, int, int, int)' lvalue Function {{.*}} 'sycl_kernel_launch' 'void (const char *, int, K<5>, int, int, int)' {{.*}}
+// CHECK-NEXT: | | |   |-ImplicitCastExpr {{.*}} 'const char *' <ArrayToPointerDecay>
+// CHECK-NEXT: | | |   | `-StringLiteral {{.*}} 'const char[14]' lvalue "_ZTS2KNILi5EE"
+// CHECK-NEXT: | | |   |-ImplicitCastExpr {{.*}} 'int' <LValueToRValue>
+// CHECK-NEXT: | | |   | `-DeclRefExpr {{.*}} 'int' lvalue ParmVar {{.*}} 'unused1' 'int'
+// CHECK-NEXT: | | |   |-CXXConstructExpr {{.*}} 'K<5>' 'void (const K<5> &) noexcept'
+// CHECK-NEXT: | | |   | `-ImplicitCastExpr {{.*}} 'const K<5>' lvalue <NoOp>
+// CHECK-NEXT: | | |   |   `-DeclRefExpr {{.*}} 'K<5>' lvalue ParmVar {{.*}} 'k' 'K<5>'
+// CHECK-NEXT: | | |   |-ImplicitCastExpr {{.*}} 'int' <LValueToRValue>
+// CHECK-NEXT: | | |   | `-DeclRefExpr {{.*}} 'int' lvalue ParmVar {{.*}} 'unused2' 'int'
+// CHECK-NEXT: | | |   |-ImplicitCastExpr {{.*}} 'int' <LValueToRValue>
+// CHECK-NEXT: | | |   | `-DeclRefExpr {{.*}} 'int' lvalue ParmVar {{.*}} 'p' 'int'
+// CHECK-NEXT: | | |   `-ImplicitCastExpr {{.*}} 'int' <LValueToRValue>
+// CHECK-NEXT: | | |     `-DeclRefExpr {{.*}} 'int' lvalue ParmVar {{.*}} 'unused3' 'int'
 // CHECK-NEXT: | | `-OutlinedFunctionDecl {{.*}}
 // CHECK-NEXT: | |   |-ImplicitParamDecl {{.*}} implicit unused1 'int'
 // CHECK-NEXT: | |   |-ImplicitParamDecl {{.*}} implicit used k 'K<5>'
@@ -263,12 +286,13 @@ void skep6(const S6 &k) {
 // CHECK-NEXT: | | |   | `-DeclRefExpr {{.*}} 'void () const' lvalue CXXMethod {{.*}} 'operator()' 'void () const'
 // CHECK-NEXT: | | |   `-DeclRefExpr {{.*}} 'const S6' lvalue ParmVar {{.*}} 'k' 'const S6 &'
 // CHECK-NEXT: | | |-CompoundStmt {{.*}}
-// CHECK-NEXT: | | | |-DeclStmt {{.*}}
-// CHECK-NEXT: | | | | `-VarDecl {{.*}} kernel_name 'const char *' extern
-// CHECK-NEXT: | | | `-BinaryOperator {{.*}} 'const char *' lvalue '='
-// CHECK-NEXT: | | |   |-DeclRefExpr {{.*}} 'const char *' lvalue Var {{.*}} 'kernel_name' 'const char *'
-// CHECK-NEXT: | | |   `-ImplicitCastExpr {{.*}} 'const char *' <ArrayToPointerDecay>
-// CHECK-NEXT: | | |     `-StringLiteral {{.*}} 'const char[14]' lvalue "_ZTS2KNILi6EE"
+// CHECK-NEXT: | | | `-CallExpr {{.*}} 'void'
+// CHECK-NEXT: | | |   |-ImplicitCastExpr {{.*}} 'void (*)(const char *, S6)' <FunctionToPointerDecay>
+// CHECK-NEXT: | | |   | `-DeclRefExpr {{.*}} 'void (const char *, S6)' lvalue Function {{.*}} 'sycl_kernel_launch' 'void (const char *, S6)' {{.*}}
+// CHECK-NEXT: | | |   |-ImplicitCastExpr {{.*}} 'const char *' <ArrayToPointerDecay>
+// CHECK-NEXT: | | |   | `-StringLiteral {{.*}} 'const char[14]' lvalue "_ZTS2KNILi6EE"
+// CHECK-NEXT: | | |   `-CXXConstructExpr {{.*}} 'S6' 'void (const S6 &) noexcept'
+// CHECK-NEXT: | | |     `-DeclRefExpr {{.*}} 'const S6' lvalue ParmVar {{.*}} 'k' 'const S6 &'
 // CHECK-NEXT: | | `-OutlinedFunctionDecl {{.*}}
 // CHECK-NEXT: | |   |-ImplicitParamDecl {{.*}} implicit used k 'const S6 &'
 // CHECK-NEXT: | |   `-CompoundStmt {{.*}}
@@ -303,12 +327,14 @@ void skep7(S7 k) {
 // CHECK-NEXT: | | |   `-ImplicitCastExpr {{.*}} 'const S7' lvalue <NoOp>
 // CHECK-NEXT: | | |     `-DeclRefExpr {{.*}} 'S7' lvalue ParmVar {{.*}} 'k' 'S7'
 // CHECK-NEXT: | | |-CompoundStmt {{.*}}
-// CHECK-NEXT: | | | |-DeclStmt {{.*}}
-// CHECK-NEXT: | | | | `-VarDecl {{.*}} kernel_name 'const char *' extern
-// CHECK-NEXT: | | | `-BinaryOperator {{.*}} 'const char *' lvalue '='
-// CHECK-NEXT: | | |   |-DeclRefExpr {{.*}} 'const char *' lvalue Var {{.*}} 'kernel_name' 'const char *'
-// CHECK-NEXT: | | |   `-ImplicitCastExpr {{.*}} 'const char *' <ArrayToPointerDecay>
-// CHECK-NEXT: | | |     `-StringLiteral {{.*}} 'const char[14]' lvalue "_ZTS2KNILi7EE"
+// CHECK-NEXT: | | | `-CallExpr {{.*}} 'void'
+// CHECK-NEXT: | | |   |-ImplicitCastExpr {{.*}} 'void (*)(const char *, S7)' <FunctionToPointerDecay>
+// CHECK-NEXT: | | |   | `-DeclRefExpr {{.*}} 'void (const char *, S7)' lvalue Function {{.*}} 'sycl_kernel_launch' 'void (const char *, S7)' {{.*}}
+// CHECK-NEXT: | | |   |-ImplicitCastExpr {{.*}} 'const char *' <ArrayToPointerDecay>
+// CHECK-NEXT: | | |   | `-StringLiteral {{.*}} 'const char[14]' lvalue "_ZTS2KNILi7EE"
+// CHECK-NEXT: | | |   `-CXXConstructExpr {{.*}} 'S7' 'void (const S7 &) noexcept'
+// CHECK-NEXT: | | |     `-ImplicitCastExpr {{.*}} 'const S7' lvalue <NoOp>
+// CHECK-NEXT: | | |       `-DeclRefExpr {{.*}} 'S7' lvalue ParmVar {{.*}} 'k' 'S7'
 // CHECK-NEXT: | | `-OutlinedFunctionDecl {{.*}}
 // CHECK-NEXT: | |   |-ImplicitParamDecl {{.*}} implicit used k 'S7'
 // CHECK-NEXT: | |   `-CompoundStmt {{.*}}
@@ -335,11 +361,96 @@ void skep8(S8 k) {
 // CHECK-NEXT: | |-SYCLKernelCallStmt {{.*}}
 // CHECK-NEXT: | | |-CompoundStmt {{.*}}
 // CHECK:      | | |-CompoundStmt {{.*}}
-// CHECK:      | | |   `-ImplicitCastExpr {{.*}} 'const char *' <ArrayToPointerDecay>
-// CHECK-NEXT: | | |     `-StringLiteral {{.*}} 'const char[12]' lvalue "_ZTS6\316\264\317\204\317\207"
+// CHECK-NEXT: | | | `-CallExpr {{.*}} 'void'
+// CHECK-NEXT: | | |   |-ImplicitCastExpr {{.*}} 'void (*)(const char *, S8)' <FunctionToPointerDecay>
+// CHECK-NEXT: | | |   | `-DeclRefExpr {{.*}} 'void (const char *, S8)' lvalue Function {{.*}} 'sycl_kernel_launch' 'void (const char *, S8)' {{.*}}
+// CHECK-NEXT: | | |   |-ImplicitCastExpr {{.*}} 'const char *' <ArrayToPointerDecay>
+// CHECK-NEXT: | | |   | `-StringLiteral {{.*}} 'const char[12]' lvalue "_ZTS6\316\264\317\204\317\207"
+// CHECK-NEXT: | | |   `-CXXConstructExpr {{.*}} 'S8' 'void (const S8 &) noexcept'
+// CHECK-NEXT: | | |     `-ImplicitCastExpr {{.*}} 'const S8' lvalue <NoOp>
+// CHECK-NEXT: | | |       `-DeclRefExpr {{.*}} 'S8' lvalue ParmVar {{.*}} 'k' 'S8'
 // CHECK:      | | `-OutlinedFunctionDecl {{.*}}
 // CHECK:      | `-SYCLKernelEntryPointAttr {{.*}}
 
+class Handler {
+template <typename KernelName, typename... Ts>
+void sycl_kernel_launch(const char *, Ts...) {}
+public:
+template<typename KNT, typename KT>
+[[clang::sycl_kernel_entry_point(KNT)]]
+void skep9(KT k, int a, int b) {
+  k(a, b);
+}
+};
+void foo() {
+  Handler H;
+  H.skep9<KN<9>>([=](int a, int b){return a+b;}, 1, 2);
+}
+
+// CHECK: | |-FunctionTemplateDecl {{.*}} skep9
+// CHECK-NEXT: | | |-TemplateTypeParmDecl {{.*}} referenced typename depth 0 index 0 KNT
+// CHECK-NEXT: | | |-TemplateTypeParmDecl {{.*}} referenced typename depth 0 index 1 KT
+// CHECK-NEXT: | | |-CXXMethodDecl {{.*}} skep9 'void (KT, int, int)' implicit-inline
+// CHECK-NEXT: | | | |-ParmVarDecl {{.*}} referenced k 'KT'
+// CHECK-NEXT: | | | |-ParmVarDecl {{.*}} referenced a 'int'
+// CHECK-NEXT: | | | |-ParmVarDecl {{.*}} referenced b 'int'
+// CHECK-NEXT: | | | |-UnresolvedSYCLKernelCallStmt {{.*}}
+// CHECK-NEXT: | | | | `-CompoundStmt {{.*}}
+// CHECK-NEXT: | | | |   `-CallExpr {{.*}} '<dependent type>'
+// CHECK-NEXT: | | | |     |-DeclRefExpr {{.*}} 'KT' lvalue ParmVar {{.*}} 'k' 'KT'
+// CHECK-NEXT: | | | |     |-DeclRefExpr {{.*}} 'int' lvalue ParmVar {{.*}} 'a' 'int'
+// CHECK-NEXT: | | | |     `-DeclRefExpr {{.*}} 'int' lvalue ParmVar {{.*}} 'b' 'int'
+// CHECK-NEXT: | | | `-SYCLKernelEntryPointAttr {{.*}} KNT
+// CHECK-NEXT: | | `-CXXMethodDecl {{.*}} used skep9 {{.*}} implicit_instantiation implicit-inline
+// CHECK-NEXT: | |   |-TemplateArgument type 'KN<9>'
+// CHECK-NEXT: | |   | `-RecordType {{.*}} 'KN<9>' canonical
+// CHECK-NEXT: | |   |   `-ClassTemplateSpecialization {{.*}}'KN'
+// CHECK-NEXT: | |   |-TemplateArgument type {{.*}}
+// CHECK-NEXT: | |   | `-RecordType {{.*}}
+// CHECK-NEXT: | |   |   `-CXXRecord {{.*}}
+// CHECK-NEXT: | |   |-ParmVarDecl {{.*}} used k {{.*}}
+// CHECK-NEXT: | |   |-ParmVarDecl {{.*}} used a 'int'
+// CHECK-NEXT: | |   |-ParmVarDecl {{.*}} used b 'int'
+// CHECK-NEXT: | |   |-SYCLKernelCallStmt {{.*}}
+// CHECK-NEXT: | |   | |-CompoundStmt {{.*}}
+// CHECK-NEXT: | |   | | `-CXXOperatorCallExpr {{.*}} 'int' '()'
+// CHECK-NEXT: | |   | |   |-ImplicitCastExpr {{.*}} 'int (*)(int, int) const' <FunctionToPointerDecay>
+// CHECK-NEXT: | |   | |   | `-DeclRefExpr {{.*}} 'int (int, int) const' lvalue CXXMethod {{.*}} 'operator()' 'int (int, int) const'
+// CHECK-NEXT: | |   | |   |-ImplicitCastExpr {{.*}} lvalue <NoOp>
+// CHECK-NEXT: | |   | |   | `-DeclRefExpr {{.*}} lvalue ParmVar {{.*}} 'k' {{.*}}
+// CHECK-NEXT: | |   | |   |-ImplicitCastExpr {{.*}} 'int' <LValueToRValue>
+// CHECK-NEXT: | |   | |   | `-DeclRefExpr {{.*}} 'int' lvalue ParmVar {{.*}} 'a' 'int'
+// CHECK-NEXT: | |   | |   `-ImplicitCastExpr {{.*}} 'int' <LValueToRValue>
+// CHECK-NEXT: | |   | |     `-DeclRefExpr {{.*}} 'int' lvalue ParmVar {{.*}} 'b' 'int'
+// CHECK-NEXT: | |   | |-CompoundStmt {{.*}}
+// CHECK-NEXT: | |   | | `-CXXMemberCallExpr {{.*}} 'void'
+// CHECK-NEXT: | |   | |   |-MemberExpr {{.*}} '<bound member function type>' ->sycl_kernel_launch {{.*}}
+// CHECK-NEXT: | |   | |   | `-CXXThisExpr {{.*}} 'Handler *' implicit this
+// CHECK-NEXT: | |   | |   |-ImplicitCastExpr {{.*}} 'const char *' <ArrayToPointerDecay>
+// CHECK-NEXT: | |   | |   | `-StringLiteral {{.*}} 'const char[14]' lvalue "_ZTS2KNILi9EE"
+// CHECK-NEXT: | |   | |   |-CXXConstructExpr {{.*}}
+// CHECK-NEXT: | |   | |   | `-ImplicitCastExpr {{.*}} lvalue <NoOp>
+// CHECK-NEXT: | |   | |   |   `-DeclRefExpr {{.*}} lvalue ParmVar {{.*}} 'k' {{.*}}
+// CHECK-NEXT: | |   | |   |-ImplicitCastExpr {{.*}} 'int' <LValueToRValue>
+// CHECK-NEXT: | |   | |   | `-DeclRefExpr {{.*}} 'int' lvalue ParmVar {{.*}} 'a' 'int'
+// CHECK-NEXT: | |   | |   `-ImplicitCastExpr {{.*}} 'int' <LValueToRValue>
+// CHECK-NEXT: | |   | |     `-DeclRefExpr {{.*}} 'int' lvalue ParmVar {{.*}} 'b' 'int'
+// CHECK-NEXT: | |   | `-OutlinedFunctionDecl {{.*}}
+// CHECK-NEXT: | |   |   |-ImplicitParamDecl {{.*}} implicit used k {{.*}}
+// CHECK-NEXT: | |   |   |-ImplicitParamDecl {{.*}} implicit used a 'int'
+// CHECK-NEXT: | |   |   |-ImplicitParamDecl {{.*}} implicit used b 'int'
+// CHECK-NEXT: | |   |   `-CompoundStmt {{.*}}
+// CHECK-NEXT: | |   |     `-CXXOperatorCallExpr {{.*}} 'int' '()'
+// CHECK-NEXT: | |   |       |-ImplicitCastExpr {{.*}} 'int (*)(int, int) const' <FunctionToPointerDecay>
+// CHECK-NEXT: | |   |       | `-DeclRefExpr {{.*}} 'int (int, int) const' lvalue CXXMethod {{.*}} 'operator()' 'int (int, int) const'
+// CHECK-NEXT: | |   |       |-ImplicitCastExpr {{.*}} lvalue <NoOp>
+// CHECK-NEXT: | |   |       | `-DeclRefExpr {{.*}} lvalue ImplicitParam {{.*}} 'k' {{.*}}
+// CHECK-NEXT: | |   |       |-ImplicitCastExpr {{.*}} 'int' <LValueToRValue>
+// CHECK-NEXT: | |   |       | `-DeclRefExpr {{.*}} 'int' lvalue ImplicitParam {{.*}} 'a' 'int'
+// CHECK-NEXT: | |   |       `-ImplicitCastExpr {{.*}} 'int' <LValueToRValue>
+// CHECK-NEXT: | |   |         `-DeclRefExpr {{.*}} 'int' lvalue ImplicitParam {{.*}} 'b' 'int'
+// CHECK-NEXT: | |   `-SYCLKernelEntryPointAttr {{.*}} struct KN<9>
+
 
 void the_end() {}
 // CHECK:      `-FunctionDecl {{.*}} the_end 'void ()'
diff --git a/clang/test/ASTSYCL/ast-dump-sycl-kernel-entry-point.cpp b/clang/test/ASTSYCL/ast-dump-sycl-kernel-entry-point.cpp
index 0171f72df0b37..7645dd4216271 100644
--- a/clang/test/ASTSYCL/ast-dump-sycl-kernel-entry-point.cpp
+++ b/clang/test/ASTSYCL/ast-dump-sycl-kernel-entry-point.cpp
@@ -28,6 +28,9 @@
 // A unique kernel name type is required for each declared kernel entry point.
 template<int, int=0> struct KN;
 
+template <typename KernelName, typename... Tys>
+void sycl_kernel_launch(const char *, Tys &&...Args) {}
+
 [[clang::sycl_kernel_entry_point(KN<1>)]]
 void skep1() {
 }
diff --git a/clang/test/CodeGenSYCL/kernel-caller-entry-point.cpp b/clang/test/CodeGenSYCL/kernel-caller-entry-point.cpp
index 3247a328ebbd3..ab1bc97cc1109 100644
--- a/clang/test/CodeGenSYCL/kernel-caller-entry-point.cpp
+++ b/clang/test/CodeGenSYCL/kernel-caller-entry-point.cpp
@@ -25,8 +25,13 @@
 
 // Test the generation of SYCL kernel caller functions. These functions are
 // generated from functions declared with the sycl_kernel_entry_point attribute
-// and emited during device compilation. They are not emitted during device
-// compilation.
+// and emited during device compilation.
+// Test the generation of SYCL kernel launch statements during host compilation.
+// These statements are calls to sycl_enqueus_kernel_launch functions or class
+// members in case skep-attributed functions are also members of the same class.
+
+template <typename KernelName, typename KernelObj>
+void sycl_kernel_launch(const char *, KernelObj) {}
 
 struct single_purpose_kernel_name;
 struct single_purpose_kernel {
@@ -47,6 +52,17 @@ void kernel_single_task(KernelType kernelFunc) {
 // Exercise code gen with kernel name types named with esoteric characters.
 struct \u03b4\u03c4\u03c7; // Delta Tau Chi (δτχ)
 
+class Handler {
+template <typename KernelName, typename... Ts>
+void sycl_kernel_launch(const char *, Ts...) {}
+public:
+template<typename KNT, typename KT>
+[[clang::sycl_kernel_entry_point(KNT)]]
+void skep(KT k, int a, int b) {
+  k(a, b);
+}
+};
+
 int main() {
   single_purpose_kernel obj;
   single_purpose_kernel_task(obj);
@@ -54,6 +70,8 @@ int main() {
   auto lambda = [=](auto) { (void) capture; };
   kernel_single_task<decltype(lambda)>(lambda);
   kernel_single_task<\u03b4\u03c4\u03c7>([](int){});
+  Handler H;
+  H.skep<class notaverygoodkernelname>([=](int a, int b){return a+b;}, 1, 2);
 }
 
 // Verify that SYCL kernel caller functions are not emitted during host
@@ -79,50 +97,105 @@ int main() {
 // CHECK-HOST-LINUX:      define dso_local void @_Z26single_purpose_kernel_task21single_purpose_kernel() #{{[0-9]+}} {
 // CHECK-HOST-LINUX-NEXT: entry:
 // CHECK-HOST-LINUX-NEXT:   %kernelFunc = alloca %struct.single_purpose_kernel, align 1
-// CHECK-HOST-LINUX-NEXT:   store ptr @.str, ptr @kernel_name, align 8
+// CHECK-HOST-LINUX-NEXT:   %agg.tmp = alloca %struct.single_purpose_kernel, align 1
+// CHECK-HOST-LINUX-NEXT:   call void @_Z18sycl_kernel_launchI26single_purpose_kernel_name21single_purpose_kernelEvPKcT0_(ptr noundef @.str)
 // CHECK-HOST-LINUX-NEXT:   ret void
 // CHECK-HOST-LINUX-NEXT: }
 //
 // CHECK-HOST-LINUX:      define internal void @_Z18kernel_single_taskIZ4mainEUlT_E_S1_EvT0_(i32 %kernelFunc.coerce) #{{[0-9]+}} {
 // CHECK-HOST-LINUX-NEXT: entry:
 // CHECK-HOST-LINUX-NEXT:   %kernelFunc = alloca %class.anon, align 4
+// CHECK-HOST-LINUX-NEXT:   %agg.tmp = alloca %class.anon, align 4
 // CHECK-HOST-LINUX-NEXT:   %coerce.dive = getelementptr inbounds nuw %class.anon, ptr %kernelFunc, i32 0, i32 0
 // CHECK-HOST-LINUX-NEXT:   store i32 %kernelFunc.coerce, ptr %coerce.dive, align 4
-// CHECK-HOST-LINUX-NEXT:   store ptr @.str.1, ptr @kernel_name, align 8
+// CHECK-HOST-LINUX-NEXT:   call void @llvm.memcpy.p0.p0.i64(ptr align 4 %agg.tmp, ptr align 4 %kernelFunc, i64 4, i1 false)
+// CHECK-HOST-LINUX-NEXT:   %coerce.dive1 = getelementptr inbounds nuw %class.anon, ptr %agg.tmp, i32 0, i32 0
+// CHECK-HOST-LINUX-NEXT:   %0 = load i32, ptr %coerce.dive1, align 4
+// CHECK-HOST-LINUX-NEXT:   call void @_Z18sycl_kernel_launchIZ4mainEUlT_E_S1_EvPKcT0_(ptr noundef @.str.1, i32 %0)
 // CHECK-HOST-LINUX-NEXT:   ret void
 // CHECK-HOST-LINUX-NEXT: }
 //
 // CHECK-HOST-LINUX:      define internal void @"_Z18kernel_single_taskI6\CE\B4\CF\84\CF\87Z4mainEUliE_EvT0_"() #{{[0-9]+}} {
 // CHECK-HOST-LINUX-NEXT: entry:
 // CHECK-HOST-LINUX-NEXT:   %kernelFunc = alloca %class.anon.0, align 1
-// CHECK-HOST-LINUX-NEXT:   store ptr @.str.2, ptr @kernel_name, align 8
+// CHECK-HOST-LINUX-NEXT:   %agg.tmp = alloca %class.anon.0, align 1
+// CHECK-HOST-LINUX-NEXT:   call void @"_Z18sycl_kernel_launchI6\CE\B4\CF\84\CF\87Z4mainEUliE_EvPKcT0_"(ptr noundef @.str.2)
 // CHECK-HOST-LINUX-NEXT:   ret void
 // CHECK-HOST-LINUX-NEXT: }
-//
+
+// CHECK-HOST-LINUX: define internal void @_ZN7Handler4skepIZ4mainE22notaverygoodkernelnameZ4mainEUliiE_EEvT0_ii(ptr noundef nonnull align 1 dereferenceable(1) %this, i32 noundef %a, i32 noundef %b) #0 align 2 {
+// CHECK-HOST-LINUX-NEXT: entry:
+// CHECK-HOST-LINUX-NEXT:   %k = alloca %class.anon.1, align 1
+// CHECK-HOST-LINUX-NEXT:   %this.addr = alloca ptr, align 8
+// CHECK-HOST-LINUX-NEXT:   %a.addr = alloca i32, align 4
+// CHECK-HOST-LINUX-NEXT:   %b.addr = alloca i32, align 4
+// CHECK-HOST-LINUX-NEXT:   %agg.tmp = alloca %class.anon.1, align 1
+// CHECK-HOST-LINUX-NEXT:   store ptr %this, ptr %this.addr, align 8
+// CHECK-HOST-LINUX-NEXT:   store i32 %a, ptr %a.addr, align 4
+// CHECK-HOST-LINUX-NEXT:   store i32 %b, ptr %b.addr, align 4
+// CHECK-HOST-LINUX-NEXT:   %this1 = load ptr, ptr %this.addr, align 8
+// CHECK-HOST-LINUX-NEXT:   %0 = load i32, ptr %a.addr, align 4
+// CHECK-HOST-LINUX-NEXT:   %1 = load i32, ptr %b.addr, align 4
+// CHECK-HOST-LINUX-NEXT:   call void @_ZN7Handler18sycl_kernel_launchIZ4mainE22notaverygoodkernelnameJZ4mainEUliiE_iiEEEvPKcDpT0_(ptr noundef nonnull align 1 dereferenceable(1) %this1, ptr noundef @.str.3, i32 noundef %0, i32 noundef %1)
+// CHECK-HOST-LINUX-NEXT:   ret void
+// CHECK-HOST-LINUX-NEXT: }
+
 // CHECK-HOST-WINDOWS:      define dso_local void @"?single_purpose_kernel_task@@YAXUsingle_purpose_kernel@@@Z"(i8 %kernelFunc.coerce) #{{[0-9]+}} {
 // CHECK-HOST-WINDOWS-NEXT: entry:
 // CHECK-HOST-WINDOWS-NEXT:   %kernelFunc = alloca %struct.single_purpose_kernel, align 1
+// CHECK-HOST-WINDOWS-NEXT:   %agg.tmp = alloca %struct.single_purpose_kernel, align 1
 // CHECK-HOST-WINDOWS-NEXT:   %coerce.dive = getelementptr inbounds nuw %struct.single_purpose_kernel, ptr %kernelFunc, i32 0, i32 0
 // CHECK-HOST-WINDOWS-NEXT:   store i8 %kernelFunc.coerce, ptr %coerce.dive, align 1
-// CHECK-HOST-WINDOWS-NEXT:   store ptr @"??_C at _0CB@KFIJOMLB at _ZTS26single_purpose_kernel_name@", ptr @"?kernel_name@?0??single_purpose_kernel_task@@YAXUsingle_purpose_kernel@@@Z at 3PEBDEB", align 8
+// CHECK-HOST-WINDOWS-NEXT:   %coerce.dive1 = getelementptr inbounds nuw %struct.single_purpose_kernel, ptr %agg.tmp, i32 0, i32 0
+// CHECK-HOST-WINDOWS-NEXT:   %0 = load i8, ptr %coerce.dive1, align 1
+// CHECK-HOST-WINDOWS-NEXT:   call void @"??$sycl_kernel_launch at Usingle_purpose_kernel_name@@Usingle_purpose_kernel@@@@YAXPEBDUsingle_purpose_kernel@@@Z"(ptr noundef @"??_C at _0CB@KFIJOMLB at _ZTS26single_purpose_kernel_name@", i8 %0)
 // CHECK-HOST-WINDOWS-NEXT:   ret void
 // CHECK-HOST-WINDOWS-NEXT: }
 //
 // CHECK-HOST-WINDOWS:      define internal void @"??$kernel_single_task at V<lambda_1>@?0??main@@9 at V1?0??2 at 9@@@YAXV<lambda_1>@?0??main@@9@@Z"(i32 %kernelFunc.coerce) #{{[0-9]+}} {
 // CHECK-HOST-WINDOWS-NEXT: entry:
 // CHECK-HOST-WINDOWS-NEXT:   %kernelFunc = alloca %class.anon, align 4
+// CHECK-HOST-WINDOWS-NEXT:   %agg.tmp = alloca %class.anon, align 4
 // CHECK-HOST-WINDOWS-NEXT:   %coerce.dive = getelementptr inbounds nuw %class.anon, ptr %kernelFunc, i32 0, i32 0
 // CHECK-HOST-WINDOWS-NEXT:   store i32 %kernelFunc.coerce, ptr %coerce.dive, align 4
-// CHECK-HOST-WINDOWS-NEXT:   store ptr @"??_C at _0BC@NHCDOLAA at _ZTSZ4mainEUlT_E_?$AA@", ptr @"?kernel_name@?0???$kernel_single_task at V<lambda_1>@?0??main@@9 at V1?0??2 at 9@@@YAXV<lambda_1>@?0??main@@9@@Z at 3PEBDEB", align 8
+// CHECK-HOST-WINDOWS-NEXT:   call void @llvm.memcpy.p0.p0.i64(ptr align 4 %agg.tmp, ptr align 4 %kernelFunc, i64 4, i1 false)
+// CHECK-HOST-WINDOWS-NEXT:   %coerce.dive1 = getelementptr inbounds nuw %class.anon, ptr %agg.tmp, i32 0, i32 0
+// CHECK-HOST-WINDOWS-NEXT:   %0 = load i32, ptr %coerce.dive1, align 4
+// CHECK-HOST-WINDOWS-NEXT:   call void @"??$sycl_kernel_launch at V<lambda_1>@?0??main@@9 at V1?0??2 at 9@@@YAXPEBDV<lambda_1>@?0??main@@9@@Z"(ptr noundef @"??_C at _0BC@NHCDOLAA at _ZTSZ4mainEUlT_E_?$AA@", i32 %0)
+//
 // CHECK-HOST-WINDOWS-NEXT:   ret void
 // CHECK-HOST-WINDOWS-NEXT: }
 //
 // CHECK-HOST-WINDOWS:      define internal void @"??$kernel_single_task at U\CE\B4\CF\84\CF\87@@V<lambda_2>@?0??main@@9@@@YAXV<lambda_2>@?0??main@@9@@Z"(i8 %kernelFunc.coerce) #{{[0-9]+}} {
 // CHECK-HOST-WINDOWS-NEXT: entry:
 // CHECK-HOST-WINDOWS-NEXT:   %kernelFunc = alloca %class.anon.0, align 1
+// CHECK-HOST-WINDOWS-NEXT:   %agg.tmp = alloca %class.anon.0, align 1
 // CHECK-HOST-WINDOWS-NEXT:   %coerce.dive = getelementptr inbounds nuw %class.anon.0, ptr %kernelFunc, i32 0, i32 0
 // CHECK-HOST-WINDOWS-NEXT:   store i8 %kernelFunc.coerce, ptr %coerce.dive, align 1
-// CHECK-HOST-WINDOWS-NEXT:   store ptr @"??_C at _0M@BCGAEMBE at _ZTS6?N?$LE?O?$IE?O?$IH?$AA@", ptr @"?kernel_name@?0???$kernel_single_task at U\CE\B4\CF\84\CF\87@@V<lambda_2>@?0??main@@9@@@YAXV<lambda_2>@?0??main@@9@@Z at 3PEBDEB", align 8
+// CHECK-HOST-WINDOWS-NEXT:   %coerce.dive1 = getelementptr inbounds nuw %class.anon.0, ptr %agg.tmp, i32 0, i32 0
+// CHECK-HOST-WINDOWS-NEXT:   %0 = load i8, ptr %coerce.dive1, align 1
+// CHECK-HOST-WINDOWS-NEXT:   call void @"??$sycl_kernel_launch at U\CE\B4\CF\84\CF\87@@V<lambda_2>@?0??main@@9@@@YAXPEBDV<lambda_2>@?0??main@@9@@Z"(ptr noundef @"??_C at _0M@BCGAEMBE at _ZTS6?N?$LE?O?$IE?O?$IH?$AA@", i8 %0)
+// CHECK-HOST-WINDOWS-NEXT:   ret void
+// CHECK-HOST-WINDOWS-NEXT: }
+
+// CHECK-HOST-WINDOWS: define internal void @"??$skep at Vnotaverygoodkernelname@?1??main@@9 at V<lambda_3>@?0??2 at 9@@Handler@@QEAAXV<lambda_3>@?0??main@@9 at HH@Z"(ptr noundef nonnull align 1 dereferenceable(1) %this, i8 %k.coerce, i32 noundef %a, i32 noundef %b) #0 align 2 {
+// CHECK-HOST-WINDOWS-NEXT: entry:
+// CHECK-HOST-WINDOWS-NEXT:   %k = alloca %class.anon.1, align 1
+// CHECK-HOST-WINDOWS-NEXT:   %b.addr = alloca i32, align 4
+// CHECK-HOST-WINDOWS-NEXT:   %a.addr = alloca i32, align 4
+// CHECK-HOST-WINDOWS-NEXT:   %this.addr = alloca ptr, align 8
+// CHECK-HOST-WINDOWS-NEXT:   %agg.tmp = alloca %class.anon.1, align 1
+// CHECK-HOST-WINDOWS-NEXT:   %coerce.dive = getelementptr inbounds nuw %class.anon.1, ptr %k, i32 0, i32 0
+// CHECK-HOST-WINDOWS-NEXT:   store i8 %k.coerce, ptr %coerce.dive, align 1
+// CHECK-HOST-WINDOWS-NEXT:   store i32 %b, ptr %b.addr, align 4
+// CHECK-HOST-WINDOWS-NEXT:   store i32 %a, ptr %a.addr, align 4
+// CHECK-HOST-WINDOWS-NEXT:   store ptr %this, ptr %this.addr, align 8
+// CHECK-HOST-WINDOWS-NEXT:   %this1 = load ptr, ptr %this.addr, align 8
+// CHECK-HOST-WINDOWS-NEXT:   %0 = load i32, ptr %b.addr, align 4
+// CHECK-HOST-WINDOWS-NEXT:   %1 = load i32, ptr %a.addr, align 4
+// CHECK-HOST-WINDOWS-NEXT:   %coerce.dive2 = getelementptr inbounds nuw %class.anon.1, ptr %agg.tmp, i32 0, i32 0
+// CHECK-HOST-WINDOWS-NEXT:   %2 = load i8, ptr %coerce.dive2, align 1
+// CHECK-HOST-WINDOWS-NEXT:   call void @"??$sycl_kernel_launch at Vnotaverygoodkernelname@?1??main@@9 at V<lambda_3>@?0??2 at 9@HH at Handler@@AEAAXPEBDV<lambda_3>@?0??main@@9 at HH@Z"(ptr noundef nonnull align 1 dereferenceable(1) %this1, ptr noundef @"??_C at _0CE@NJIGCEIA at _ZTSZ4mainE22notaverygoodkerneln@", i8 %2, i32 noundef %1, i32 noundef %0)
 // CHECK-HOST-WINDOWS-NEXT:   ret void
 // CHECK-HOST-WINDOWS-NEXT: }
 
diff --git a/clang/test/CodeGenSYCL/unique_stable_name_windows_diff.cpp b/clang/test/CodeGenSYCL/unique_stable_name_windows_diff.cpp
index 14366a092a1fe..63db83c02bbef 100644
--- a/clang/test/CodeGenSYCL/unique_stable_name_windows_diff.cpp
+++ b/clang/test/CodeGenSYCL/unique_stable_name_windows_diff.cpp
@@ -1,6 +1,8 @@
 // RUN: %clang_cc1 -triple spir64-unknown-unknown -aux-triple x86_64-pc-windows-msvc -fsycl-is-device -disable-llvm-passes -emit-llvm %s -o - | FileCheck %s '-D$ADDRSPACE=addrspace(1) '
 // RUN: %clang_cc1 -triple x86_64-pc-windows-msvc -fsycl-is-host -disable-llvm-passes -emit-llvm %s -o - | FileCheck %s '-D$ADDRSPACE='
 
+template <typename KernelName, typename KernelObj>
+void sycl_kernel_launch(const char *, KernelObj) {}
 
 template<typename KN, typename Func>
 [[clang::sycl_kernel_entry_point(KN)]] void kernel(Func F){
diff --git a/clang/test/SemaSYCL/sycl-host-kernel-launch.cpp b/clang/test/SemaSYCL/sycl-host-kernel-launch.cpp
new file mode 100644
index 0000000000000..eda0c4da489a9
--- /dev/null
+++ b/clang/test/SemaSYCL/sycl-host-kernel-launch.cpp
@@ -0,0 +1,199 @@
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++17 -fsyntax-only -fsycl-is-host -fcxx-exceptions -verify=host,expected %s
+// RUN: %clang_cc1 -triple x86_64-windows-msvc -std=c++17 -fsyntax-only -fsycl-is-host -fcxx-exceptions -verify=host,expected %s
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++17 -fsyntax-only -fsycl-is-device -fcxx-exceptions -verify=device,expected %s
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++20 -fsyntax-only -fsycl-is-host -fcxx-exceptions -verify=host,expected %s
+
+// A unique kernel name type is required for each declared kernel entry point.
+template<int, int = 0> struct KN;
+
+[[clang::sycl_kernel_entry_point(KN<1>)]]
+void nolauncher() {} 
+// host-error at -1 {{unable to find suitable 'sycl_kernel_launch' function for host code synthesis}}
+// device-warning at -2 {{unable to find suitable 'sycl_kernel_launch' function for host code synthesis}}
+// expected-note at -3 {{define 'sycl_kernel_launch' function template to fix}}
+
+void sycl_kernel_launch(const char *, int arg);
+// expected-note at -1 {{declared as a non-template here}}
+
+[[clang::sycl_kernel_entry_point(KN<2>)]]
+void nontemplatel() {}
+// host-error at -1 {{unable to find suitable 'sycl_kernel_launch' function for host code synthesis}}
+// device-warning at -2 {{unable to find suitable 'sycl_kernel_launch' function for host code synthesis}}
+// expected-note at -3 {{define 'sycl_kernel_launch' function template to fix}}
+// expected-error at -4 {{'sycl_kernel_launch' following the 'template' keyword does not refer to a template}}
+
+template <typename KernName>
+void sycl_kernel_launch(const char *, int arg);
+// expected-note at -1 {{candidate function template not viable: requires 2 arguments, but 1 was provided}}
+// expected-note at -2 2{{candidate function template not viable: no known conversion from 'Kern' to 'int' for 2nd argument}}
+
+[[clang::sycl_kernel_entry_point(KN<3>)]]
+void notenoughargs() {}
+// expected-error at -1 {{no matching function for call to 'sycl_kernel_launch'}}
+// FIXME: Should this also say "no suitable function for host code synthesis"?
+
+
+template <typename KernName>
+void sycl_kernel_launch(const char *, bool arg = 1);
+// expected-note at -1 2{{candidate function template not viable: no known conversion from 'Kern' to 'bool' for 2nd argument}}
+
+[[clang::sycl_kernel_entry_point(KN<4>)]]
+void enoughargs() {}
+
+namespace boop {
+template <typename KernName, typename KernelObj>
+void sycl_kernel_launch(const char *, KernelObj);
+
+template <typename KernName, typename KernelObj>
+[[clang::sycl_kernel_entry_point(KernName)]]
+void iboop(KernelObj Kernel) {
+  Kernel();
+}
+}
+
+template <typename KernName, typename KernelObj>
+[[clang::sycl_kernel_entry_point(KernName)]]
+void idontboop(KernelObj Kernel) {
+  Kernel();
+}
+// expected-error at -3 {{no matching function for call to 'sycl_kernel_launch'}}
+
+struct Kern {
+  int a;
+  int *b;
+  Kern(int _a, int* _b) : a(_a), b(_b) {}
+  void operator()(){ *b = a;}
+};
+
+void foo() {
+  int *a;
+  Kern b(1, a);
+  idontboop<KN<6>>(b);
+  // expected-note at -1 {{in instantiation of function template specialization 'idontboop<KN<6>, Kern>' requested here}}
+  boop::iboop<KN<7>>(b);
+}
+
+class MaybeHandler {
+
+template <typename KernName>
+void sycl_kernel_launch(const char *);
+
+template <typename KernName, typename... Tys>
+void sycl_kernel_launch(const char *, Tys ...Args);
+
+public:
+
+template <typename KernName, typename KernelObj>
+[[clang::sycl_kernel_entry_point(KernName)]]
+void entry(KernelObj Kernel) {
+  Kernel();
+}
+};
+
+class MaybeHandler2 {
+
+template <typename KernName, typename... Tys>
+static void sycl_kernel_launch(const char *, Tys ...Args);
+
+public:
+
+template <typename KernName, typename KernelObj>
+[[clang::sycl_kernel_entry_point(KernName)]]
+void entry(KernelObj Kernel) {
+  Kernel();
+}
+};
+
+class MaybeHandler3 {
+
+template <typename KernName, typename... Tys>
+static void sycl_kernel_launch(const char *, Tys ...Args);
+
+public:
+
+template <typename KernName, typename KernelObj>
+[[clang::sycl_kernel_entry_point(KernName)]]
+static void entry(KernelObj Kernel) {
+  Kernel();
+}
+};
+
+class MaybeHandler4 {
+
+template <typename KernName, typename... Tys>
+void sycl_kernel_launch(const char *, Tys ...Args);
+
+public:
+
+template <typename KernName, typename KernelObj>
+[[clang::sycl_kernel_entry_point(KernName)]]
+static void entry(KernelObj Kernel) { 
+  // expected-error at -1 {{call to non-static member function without an object argument}}
+  // FIXME: Should that be clearer?
+  Kernel();
+}
+};
+
+template<typename>
+struct base_handler {
+  template<typename KNT, typename... Ts>
+  void sycl_kernel_launch(const char*, Ts...) {}
+};
+struct derived_handler : base_handler<derived_handler> {
+  template<typename KNT, typename KT>
+  [[clang::sycl_kernel_entry_point(KNT)]]
+  void entry(KT k) { k(); }
+};
+
+template<int N>
+struct derived_handler_t : base_handler<derived_handler_t<N>> {
+  template<typename KNT, typename KT>
+// FIXME this fails because accessing members of dependent bases requires
+// explicit qualification.
+  [[clang::sycl_kernel_entry_point(KNT)]]
+  void entry(KT k) { k(); }
+  // expected-error at -1 {{no matching function for call to 'sycl_kernel_launch'}}
+};
+
+template<typename KNT>
+struct kernel_launcher {
+  template<typename... Ts>
+  void operator()(const char*, Ts...) const {}
+};
+
+namespace var {
+template<typename KNT>
+kernel_launcher<KNT> sycl_kernel_launch;
+
+struct handler {
+  template<typename KNT, typename KT>
+  [[clang::sycl_kernel_entry_point(KNT)]]
+  void entry(KT k) { k(); }
+};
+}
+
+
+void bar() {
+  int *a;
+  Kern b(1, a);
+  MaybeHandler H;
+  MaybeHandler2 H1;
+  MaybeHandler3 H2;
+  MaybeHandler4 H3;
+  H.entry<KN<8>>(b);
+  H1.entry<KN<9>>(b);
+  H2.entry<KN<10>>(b);
+  H3.entry<KN<11>>(b);
+
+  derived_handler H5;
+  H5.entry<KN<12>>(b);
+
+  derived_handler_t<13> H6;
+  H6.entry<KN<13>>(b); //expected-note {{in instantiation of function template specialization}}
+
+  var::handler h;
+  h.entry<KN<14>>(b);
+}
+
+
+
diff --git a/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-appertainment.cpp b/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-appertainment.cpp
index 3f07feb87c9a1..c181f76321a26 100644
--- a/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-appertainment.cpp
+++ b/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-appertainment.cpp
@@ -40,6 +40,10 @@ struct coroutine_traits {
 // A unique kernel name type is required for each declared kernel entry point.
 template<int, int = 0> struct KN;
 
+// A launcher function definition required for host code synthesis to silence
+// complains.
+template <typename KernelName, typename... Tys>
+void sycl_kernel_launch(const char *, Tys &&...Args) {}
 
 ////////////////////////////////////////////////////////////////////////////////
 // Valid declarations.
diff --git a/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-grammar.cpp b/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-grammar.cpp
index fd1f00ae05d7a..1cdd48f1e5840 100644
--- a/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-grammar.cpp
+++ b/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-grammar.cpp
@@ -10,6 +10,10 @@
 template<int> struct ST; // #ST-decl
 template<int N> using TTA = ST<N>; // #TTA-decl
 
+// A launcher function definition required for host code synthesis to silence
+// complains.
+template <typename KernelName, typename... Tys>
+void sycl_kernel_launch(const char *, Tys &&...Args) {}
 
 ////////////////////////////////////////////////////////////////////////////////
 // Valid declarations.
diff --git a/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-kernel-name-module.cpp b/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-kernel-name-module.cpp
index 8788e147a2ae4..44a3ce6f3640a 100644
--- a/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-kernel-name-module.cpp
+++ b/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-kernel-name-module.cpp
@@ -17,6 +17,11 @@ module M2 { header "m2.h" }
 #--- common.h
 template<int> struct KN;
 
+// A launcher function definition required for host code synthesis to silence
+// complains.
+template <typename KernelName, typename... Tys>
+void sycl_kernel_launch(const char *, Tys &&...Args) {}
+
 [[clang::sycl_kernel_entry_point(KN<1>)]]
 void common_test1() {}
 
@@ -25,7 +30,6 @@ template<typename T>
 void common_test2() {}
 template void common_test2<KN<2>>();
 
-
 #--- m1.h
 #include "common.h"
 
diff --git a/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-kernel-name-pch.cpp b/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-kernel-name-pch.cpp
index 0575a7a5a67eb..0e6d1a6c57e39 100644
--- a/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-kernel-name-pch.cpp
+++ b/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-kernel-name-pch.cpp
@@ -15,6 +15,11 @@
 #--- pch.h
 template<int> struct KN;
 
+// A launcher function definition required for host code synthesis to silence
+// complains.
+template <typename KernelName, typename... Tys>
+void sycl_kernel_launch(const char *, Tys &&...Args) {}
+
 [[clang::sycl_kernel_entry_point(KN<1>)]]
 void pch_test1() {} // << expected previous declaration note here.
 
@@ -26,11 +31,11 @@ template void pch_test2<KN<2>>();
 
 #--- test.cpp
 // expected-error at +3 {{the 'clang::sycl_kernel_entry_point' kernel name argument conflicts with a previous declaration}}
-// expected-note at pch.h:4 {{previous declaration is here}}
+// expected-note at pch.h:9 {{previous declaration is here}}
 [[clang::sycl_kernel_entry_point(KN<1>)]]
 void test1() {}
 
 // expected-error at +3 {{the 'clang::sycl_kernel_entry_point' kernel name argument conflicts with a previous declaration}}
-// expected-note at pch.h:8 {{previous declaration is here}}
+// expected-note at pch.h:13 {{previous declaration is here}}
 [[clang::sycl_kernel_entry_point(KN<2>)]]
 void test2() {}
diff --git a/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-kernel-name.cpp b/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-kernel-name.cpp
index 5a3b43be66daf..7b525abadd2c3 100644
--- a/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-kernel-name.cpp
+++ b/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-kernel-name.cpp
@@ -9,6 +9,12 @@
 // specification.
 
 struct S1;
+
+// A launcher function definition required for host code synthesis to silence
+// complains.
+template <typename KernelName, typename... Tys>
+void sycl_kernel_launch(const char *, Tys &&...Args) {}
+
 // expected-warning at +3 {{redundant 'clang::sycl_kernel_entry_point' attribute}}
 // expected-note at +1  {{previous attribute is here}}
 [[clang::sycl_kernel_entry_point(S1),
diff --git a/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-sfinae.cpp b/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-sfinae.cpp
index 3689adaab9b5b..9674dac456f9f 100644
--- a/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-sfinae.cpp
+++ b/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-sfinae.cpp
@@ -10,6 +10,11 @@
 // attribute during instantiation of a specialization unless that specialization
 // is selected by overload resolution.
 
+// A launcher function definition required for host code synthesis to silence
+// complains.
+template <typename KernelName, typename... Tys>
+void sycl_kernel_launch(const char *, Tys &&...Args) {}
+
 // FIXME: C++23 [temp.expl.spec]p12 states:
 // FIXME:   ... Similarly, attributes appearing in the declaration of a template
 // FIXME:   have no effect on an explicit specialization of that template.
diff --git a/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-this.cpp b/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-this.cpp
index fc0640e1900cb..7b8fc6c9a7630 100644
--- a/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-this.cpp
+++ b/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-this.cpp
@@ -22,6 +22,11 @@ struct type_info {
 };
 } // namespace std
 
+// A launcher function definition required for host code synthesis to silence
+// complains.
+template <typename KernelName, typename... Tys>
+void sycl_kernel_launch(const char *, Tys &&...Args) {}
+
 ////////////////////////////////////////////////////////////////////////////////
 // Valid declarations.
 ////////////////////////////////////////////////////////////////////////////////
diff --git a/clang/tools/libclang/CXCursor.cpp b/clang/tools/libclang/CXCursor.cpp
index 17f485e5c78a5..d31d2c0c9bb67 100644
--- a/clang/tools/libclang/CXCursor.cpp
+++ b/clang/tools/libclang/CXCursor.cpp
@@ -383,6 +383,7 @@ CXCursor cxcursor::MakeCXCursor(const Stmt *S, const Decl *Parent,
     break;
 
   case Stmt::SYCLKernelCallStmtClass:
+  case Stmt::UnresolvedSYCLKernelCallStmtClass:
     K = CXCursor_UnexposedStmt;
     break;
 

>From d82486c4b1d8da8ee5675013addeedea8d89ecce Mon Sep 17 00:00:00 2001
From: Mariya Podchishchaeva <mariya.podchishchaeva at intel.com>
Date: Wed, 1 Oct 2025 19:52:56 +0200
Subject: [PATCH 06/29] [SYCL-Upstreaming] Fix a crash (#52)

In case a function with skep attribute is instantiated two times with
the same kernel name the attribute is invalid due to the conflicting name.
Make sure to exit from instantiation of UnresolvedSYCLKernelCallStmt in
this case.
---
 clang/lib/Sema/TreeTransform.h                |  5 +++++
 ...cl-kernel-entry-point-attr-kernel-name.cpp | 22 +++++++++++++++++++
 2 files changed, 27 insertions(+)

diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 671f5440d36cf..c6efabdfadf43 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -13058,6 +13058,11 @@ ExprResult TreeTransform<Derived>::TransformSYCLUniqueStableNameExpr(
 template <typename Derived>
 StmtResult TreeTransform<Derived>::TransformUnresolvedSYCLKernelCallStmt(
     UnresolvedSYCLKernelCallStmt *S) {
+  auto *FD = cast<FunctionDecl>(SemaRef.CurContext);
+  const auto *SKEPAttr = FD->getAttr<SYCLKernelEntryPointAttr>();
+  if (!SKEPAttr || SKEPAttr->isInvalidAttr())
+    return StmtError();
+
   ExprResult IdExpr = getDerived().TransformExpr(S->getKernelLaunchIdExpr());
 
   if (IdExpr.isInvalid())
diff --git a/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-kernel-name.cpp b/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-kernel-name.cpp
index 7b525abadd2c3..e2e6bf3314614 100644
--- a/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-kernel-name.cpp
+++ b/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-kernel-name.cpp
@@ -124,3 +124,25 @@ struct B19 {
 };
 // expected-note at +1 {{in instantiation of template class 'B19<int>' requested here}}
 B19<int> b19;
+
+struct auto_name;
+
+// expected-error at +4 {{the 'clang::sycl_kernel_entry_point' kernel name argument conflicts with a previous declaration}}
+// expected-note at +3 {{previous declaration is here}}
+template <typename KernelName, typename KernelType>
+[[clang::sycl_kernel_entry_point(KernelName)]]
+void __kernel_single_task(const KernelType KernelFunc) {
+  KernelFunc();
+}
+
+template <typename KernelType, typename KernelName = auto_name>
+void pf(KernelType K) {
+  // expected-note at +1 {{requested here}}
+  __kernel_single_task<KernelName>(K);
+}
+
+void foo() {
+  pf([](){});
+  // expected-note at +1 {{requested here}}
+  pf([](){});
+}

>From 85fdc2d2bab65d6c7018b7ee8f89eac7daa1c014 Mon Sep 17 00:00:00 2001
From: Mariya Podchishchaeva <mariya.podchishchaeva at intel.com>
Date: Wed, 1 Oct 2025 20:00:08 +0200
Subject: [PATCH 07/29] [SYCL-Upstreaming] Fix a crash an argument of skep
 function is not trivially-copyable (#53)

device-copyable doesn't mean trivially-copyable, so we may encounter
arguments that need cleanup. Adds test that verifies presence of the
dtor call in the synthesized code.
---
 clang/lib/Sema/SemaSYCL.cpp                   |  2 +-
 .../CodeGenSYCL/kernel-caller-entry-point.cpp | 47 +++++++++++++++++++
 2 files changed, 48 insertions(+), 1 deletion(-)

diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp
index 12512b5d65113..2a7bdde93f007 100644
--- a/clang/lib/Sema/SemaSYCL.cpp
+++ b/clang/lib/Sema/SemaSYCL.cpp
@@ -511,7 +511,7 @@ StmtResult BuildSYCLKernelLaunchStmt(Sema &SemaRef,
     if (LaunchResult.isInvalid())
       return StmtError();
 
-    Stmts.push_back(LaunchResult.get());
+    Stmts.push_back(SemaRef.MaybeCreateExprWithCleanups(LaunchResult).get());
   }
 
   return CompoundStmt::Create(SemaRef.getASTContext(), Stmts,
diff --git a/clang/test/CodeGenSYCL/kernel-caller-entry-point.cpp b/clang/test/CodeGenSYCL/kernel-caller-entry-point.cpp
index ab1bc97cc1109..d2b8addae3ced 100644
--- a/clang/test/CodeGenSYCL/kernel-caller-entry-point.cpp
+++ b/clang/test/CodeGenSYCL/kernel-caller-entry-point.cpp
@@ -63,6 +63,23 @@ void skep(KT k, int a, int b) {
 }
 };
 
+struct auto_name;
+
+template <typename KernelName, typename KernelType>
+[[clang::sycl_kernel_entry_point(KernelName)]]
+void __kernel_single_task(const KernelType KernelFunc) {
+  KernelFunc();
+}
+
+template <typename KernelType, typename KernelName = auto_name>
+void pf(KernelType K) {
+  __kernel_single_task<KernelName>(K);
+}
+struct DCopyable {
+  int i;
+  ~DCopyable();
+};
+
 int main() {
   single_purpose_kernel obj;
   single_purpose_kernel_task(obj);
@@ -72,6 +89,9 @@ int main() {
   kernel_single_task<\u03b4\u03c4\u03c7>([](int){});
   Handler H;
   H.skep<class notaverygoodkernelname>([=](int a, int b){return a+b;}, 1, 2);
+
+  DCopyable b;
+  pf([b](){});
 }
 
 // Verify that SYCL kernel caller functions are not emitted during host
@@ -140,6 +160,17 @@ int main() {
 // CHECK-HOST-LINUX-NEXT:   ret void
 // CHECK-HOST-LINUX-NEXT: }
 
+// CHECK-HOST-LINUX: define internal void @_Z20__kernel_single_taskI9auto_nameZ4mainEUlvE_EvT0_(ptr noundef %KernelFunc)
+// CHECK-HOST-LINUX-NEXT: entry:
+// CHECK-HOST-LINUX-NEXT:   %KernelFunc.indirect_addr = alloca ptr, align 8
+// CHECK-HOST-LINUX-NEXT:   %agg.tmp = alloca %class.anon.3, align 4
+// CHECK-HOST-LINUX-NEXT:   store ptr %KernelFunc, ptr %KernelFunc.indirect_addr, align 8
+// CHECK-HOST-LINUX-NEXT:   call void @llvm.memcpy.p0.p0.i64(ptr align 4 %agg.tmp, ptr align 4 %KernelFunc, i64 4, i1 false)
+// CHECK-HOST-LINUX-NEXT:   call void @_Z18sycl_kernel_launchI9auto_nameZ4mainEUlvE_EvPKcT0_(ptr noundef @.str.4, ptr noundef %agg.tmp)
+// CHECK-HOST-LINUX-NEXT:   call void @_ZZ4mainENUlvE_D1Ev(ptr noundef nonnull align 4 dereferenceable(4) %agg.tmp) #4
+// CHECK-HOST-LINUX-NEXT:   ret void
+// CHECK-HOST-LINUX-NEXT: }
+
 // CHECK-HOST-WINDOWS:      define dso_local void @"?single_purpose_kernel_task@@YAXUsingle_purpose_kernel@@@Z"(i8 %kernelFunc.coerce) #{{[0-9]+}} {
 // CHECK-HOST-WINDOWS-NEXT: entry:
 // CHECK-HOST-WINDOWS-NEXT:   %kernelFunc = alloca %struct.single_purpose_kernel, align 1
@@ -199,6 +230,22 @@ int main() {
 // CHECK-HOST-WINDOWS-NEXT:   ret void
 // CHECK-HOST-WINDOWS-NEXT: }
 
+// CHECK-HOST-WINDOWS: define internal void @"??$__kernel_single_task at Uauto_name@@V<lambda_4>@?0??main@@9@@@YAXV<lambda_4>@?0??main@@9@@Z"(i32 %KernelFunc.coerce)
+// CHECK-HOST-WINDOWS-NEXT: entry:
+// CHECK-HOST-WINDOWS-NEXT:   %KernelFunc = alloca %class.anon.3, align 4
+// CHECK-HOST-WINDOWS-NEXT:   %agg.tmp = alloca %class.anon.3, align 4
+// CHECK-HOST-WINDOWS-NEXT:   %coerce.dive = getelementptr inbounds nuw %class.anon.3, ptr %KernelFunc, i32 0, i32 0
+// CHECK-HOST-WINDOWS-NEXT:   %coerce.dive1 = getelementptr inbounds nuw %struct.DCopyable, ptr %coerce.dive, i32 0, i32 0
+// CHECK-HOST-WINDOWS-NEXT:   store i32 %KernelFunc.coerce, ptr %coerce.dive1, align 4
+// CHECK-HOST-WINDOWS-NEXT:   call void @llvm.memcpy.p0.p0.i64(ptr align 4 %agg.tmp, ptr align 4 %KernelFunc, i64 4, i1 false)
+// CHECK-HOST-WINDOWS-NEXT:   %coerce.dive2 = getelementptr inbounds nuw %class.anon.3, ptr %agg.tmp, i32 0, i32 0
+// CHECK-HOST-WINDOWS-NEXT:   %coerce.dive3 = getelementptr inbounds nuw %struct.DCopyable, ptr %coerce.dive2, i32 0, i32 0
+// CHECK-HOST-WINDOWS-NEXT:   %0 = load i32, ptr %coerce.dive3, align 4
+// CHECK-HOST-WINDOWS-NEXT:   call void @"??$sycl_kernel_launch at Uauto_name@@V<lambda_4>@?0??main@@9@@@YAXPEBDV<lambda_4>@?0??main@@9@@Z"(ptr noundef @"??_C at _0P@HMAAEHI at _ZTS9auto_name?$AA@", i32 %0)
+// CHECK-HOST-WINDOWS-NEXT:   call void @"??1<lambda_4>@?0??main@@9 at QEAA@XZ"(ptr noundef nonnull align 4 dereferenceable(4) %KernelFunc)
+// CHECK-HOST-WINDOWS-NEXT:   ret void
+// CHECK-HOST-WINDOWS-NEXT: }
+
 // Verify that SYCL kernel caller functions are emitted for each device target.
 //
 // main() shouldn't be emitted in device code.

>From 7f3b904fa37223e4abbeced68ae63e0f9773343b Mon Sep 17 00:00:00 2001
From: Tom Honermann <tom.honermann at intel.com>
Date: Mon, 10 Nov 2025 15:11:51 -0800
Subject: [PATCH 08/29] Correct expected AST output for a test following a
 rebase.

---
 clang/test/ASTSYCL/ast-dump-sycl-kernel-call-stmt.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/test/ASTSYCL/ast-dump-sycl-kernel-call-stmt.cpp b/clang/test/ASTSYCL/ast-dump-sycl-kernel-call-stmt.cpp
index d64db19c8304e..bf9e2e22d67d4 100644
--- a/clang/test/ASTSYCL/ast-dump-sycl-kernel-call-stmt.cpp
+++ b/clang/test/ASTSYCL/ast-dump-sycl-kernel-call-stmt.cpp
@@ -401,7 +401,7 @@ void foo() {
 // CHECK-NEXT: | | | |     |-DeclRefExpr {{.*}} 'int' lvalue ParmVar {{.*}} 'a' 'int'
 // CHECK-NEXT: | | | |     `-DeclRefExpr {{.*}} 'int' lvalue ParmVar {{.*}} 'b' 'int'
 // CHECK-NEXT: | | | `-SYCLKernelEntryPointAttr {{.*}} KNT
-// CHECK-NEXT: | | `-CXXMethodDecl {{.*}} used skep9 {{.*}} implicit_instantiation implicit-inline
+// CHECK-NEXT: | | `-CXXMethodDecl {{.*}} used skep9 {{.*}} implicit_instantiation implicit-inline instantiated_from 0x{{.*}}
 // CHECK-NEXT: | |   |-TemplateArgument type 'KN<9>'
 // CHECK-NEXT: | |   | `-RecordType {{.*}} 'KN<9>' canonical
 // CHECK-NEXT: | |   |   `-ClassTemplateSpecialization {{.*}}'KN'

>From 6e86fe35d6b6011173d65e86821d7e03c2dbbe4c Mon Sep 17 00:00:00 2001
From: Tom Honermann <tom.honermann at intel.com>
Date: Fri, 14 Nov 2025 14:02:15 -0800
Subject: [PATCH 09/29] Misc cleanup.

- Added/edited lots of comments.
- Expanded testing for sycl_kernel_launch lookup and reorganized the tests
  to make it easier to identify and/or plug testing gaps.
- Added a missing sycl_kernel_entry_point attribute in a test.
- Reordered various declarations for better grouping and consistency.
- Renamed some variables and functions.
- Removed an unnecessary include directive.
- Adjusted the location used for the implicit sycl_kernel_launch call. The
  opening brace of the original function body is used where available and
  the general function location is used otherwise.
- Corrected lookup to unconditionally look for a template name; previously
  a spurious error about a 'template' keyword could be issued.
- Added missing code gen checks for use of a member function as the SYCL
  kernel entry point function.
- Other misc style edits for consistency.
---
 clang/include/clang/AST/StmtSYCL.h            |  21 +-
 clang/include/clang/Sema/SemaSYCL.h           |  27 +-
 clang/lib/AST/ComputeDependence.cpp           |   1 -
 clang/lib/CodeGen/CGStmt.cpp                  |   2 +-
 clang/lib/Sema/SemaDecl.cpp                   |  20 +-
 clang/lib/Sema/SemaSYCL.cpp                   | 136 +++---
 clang/lib/Sema/TreeTransform.h                |   1 -
 .../ast-dump-sycl-kernel-call-stmt.cpp        |  18 +-
 .../ast-dump-sycl-kernel-entry-point.cpp      |   4 +-
 .../ast-print-sycl-kernel-call.cpp            |  13 +-
 .../CodeGenSYCL/kernel-caller-entry-point.cpp | 225 +++++----
 .../unique_stable_name_windows_diff.cpp       |   4 +-
 .../test/SemaSYCL/sycl-host-kernel-launch.cpp | 199 --------
 ...-kernel-entry-point-attr-appertainment.cpp |   7 +-
 .../sycl-kernel-entry-point-attr-grammar.cpp  |   7 +-
 ...el-entry-point-attr-kernel-name-module.cpp |   8 +-
 ...ernel-entry-point-attr-kernel-name-pch.cpp |  11 +-
 ...cl-kernel-entry-point-attr-kernel-name.cpp |  29 +-
 .../sycl-kernel-entry-point-attr-sfinae.cpp   |   7 +-
 .../sycl-kernel-entry-point-attr-this.cpp     |   7 +-
 clang/test/SemaSYCL/sycl-kernel-launch.cpp    | 448 ++++++++++++++++++
 21 files changed, 750 insertions(+), 445 deletions(-)
 rename clang/test/{AST => ASTSYCL}/ast-print-sycl-kernel-call.cpp (61%)
 delete mode 100644 clang/test/SemaSYCL/sycl-host-kernel-launch.cpp
 create mode 100644 clang/test/SemaSYCL/sycl-kernel-launch.cpp

diff --git a/clang/include/clang/AST/StmtSYCL.h b/clang/include/clang/AST/StmtSYCL.h
index c8da4987321a9..cce62466eec10 100644
--- a/clang/include/clang/AST/StmtSYCL.h
+++ b/clang/include/clang/AST/StmtSYCL.h
@@ -100,23 +100,30 @@ class SYCLKernelCallStmt : public Stmt {
 };
 
 // UnresolvedSYCLKernelCallStmt represents an invocation of a SYCL kernel in
-// a dependent context for which lookup of the sycl_enqueue_kernel_launch
-// identifier cannot be performed. These statements are transformed to
-// SYCLKernelCallStmt during template instantiation.
+// a dependent context for which lookup of the sycl_kernel_launch identifier
+// cannot be performed. These statements are transformed to SYCLKernelCallStmt
+// during template instantiation.
 class UnresolvedSYCLKernelCallStmt : public Stmt {
   friend class ASTStmtReader;
+  friend class ASTStmtWriter;
+
+private:
   Stmt *OriginalStmt = nullptr;
   // KernelLaunchIdExpr stores an UnresolvedLookupExpr or UnresolvedMemberExpr
   // corresponding to the SYCL kernel launch function for which a call
   // will be synthesized during template instantiation.
   Expr *KernelLaunchIdExpr = nullptr;
+
   UnresolvedSYCLKernelCallStmt(CompoundStmt *CS, Expr *IdExpr)
       : Stmt(UnresolvedSYCLKernelCallStmtClass), OriginalStmt(CS),
         KernelLaunchIdExpr(IdExpr) {}
 
-  void setKernelLaunchIdExpr(Expr *IdExpr) { KernelLaunchIdExpr = IdExpr; }
+  /// Set the original statement.
   void setOriginalStmt(CompoundStmt *CS) { OriginalStmt = CS; }
 
+  /// Set the kernel launch ID expression.
+  void setKernelLaunchIdExpr(Expr *IdExpr) { KernelLaunchIdExpr = IdExpr; }
+
 public:
   static UnresolvedSYCLKernelCallStmt *
   Create(const ASTContext &C, CompoundStmt *CS, Expr *IdExpr) {
@@ -127,12 +134,16 @@ class UnresolvedSYCLKernelCallStmt : public Stmt {
     return new (C) UnresolvedSYCLKernelCallStmt(nullptr, nullptr);
   }
 
-  Expr *getKernelLaunchIdExpr() const { return KernelLaunchIdExpr; }
+  /// Retrieve the original statement.
   CompoundStmt *getOriginalStmt() { return cast<CompoundStmt>(OriginalStmt); }
   const CompoundStmt *getOriginalStmt() const {
     return cast<CompoundStmt>(OriginalStmt);
   }
 
+  /// Retrieve the kernel launch ID expression.
+  Expr *getKernelLaunchIdExpr() { return KernelLaunchIdExpr; }
+  const Expr *getKernelLaunchIdExpr() const { return KernelLaunchIdExpr; }
+
   SourceLocation getBeginLoc() const LLVM_READONLY {
     return getOriginalStmt()->getBeginLoc();
   }
diff --git a/clang/include/clang/Sema/SemaSYCL.h b/clang/include/clang/Sema/SemaSYCL.h
index 76046b765c0d6..5018c1093b5c6 100644
--- a/clang/include/clang/Sema/SemaSYCL.h
+++ b/clang/include/clang/Sema/SemaSYCL.h
@@ -66,11 +66,32 @@ class SemaSYCL : public SemaBase {
 
   void CheckSYCLExternalFunctionDecl(FunctionDecl *FD);
   void CheckSYCLEntryPointFunctionDecl(FunctionDecl *FD);
+
+  /// Builds an expression for the lookup of a 'sycl_kernel_launch' template
+  /// with 'KernelName' as an explicit template argument. Lookup is performed
+  /// as if from the first statement of the body of 'FD' and thus requires
+  /// searching the scopes that exist at parse time. This function therefore
+  /// requires the current semantic context to be the definition of 'FD'. In a
+  /// dependent context, the returned expression will be an UnresolvedLookupExpr
+  /// or an UnresolvedMemberExpr. In a non-dependent context, the returned
+  /// expression will be a DeclRefExpr or MemberExpr. If lookup fails, a null
+  /// error result is returned. The resulting expression is intended to be
+  /// passed as the 'LaunchIdExpr' argument in a call to either
+  /// BuildSYCLKernelCallStmt() or BuildUnresolvedSYCLKernelCallStmt() after
+  /// the function body has been parsed.
+  ExprResult BuildSYCLKernelLaunchIdExpr(FunctionDecl *FD, QualType KernelName);
+
+  /// Builds a SYCLKernelCallStmt to wrap 'Body' and to be used as the body of
+  /// 'FD'. 'LaunchIdExpr' specifies the lookup result returned by a previous
+  /// call to BuildSYCLKernelLaunchIdExpr().
   StmtResult BuildSYCLKernelCallStmt(FunctionDecl *FD, CompoundStmt *Body,
                                      Expr *LaunchIdExpr);
-  ExprResult BuildSYCLKernelLaunchIdExpr(FunctionDecl *FD, QualType KNT);
-  StmtResult BuildUnresolvedSYCLKernelCallStmt(CompoundStmt *CS,
-                                                     Expr *IdExpr);
+
+  /// Builds an UnresolvedSYCLKernelCallStmt to wrap 'Body'. 'LaunchIdExpr'
+  /// specifies the lookup result returned by a previous call to
+  /// BuildSYCLKernelLaunchIdExpr().
+  StmtResult BuildUnresolvedSYCLKernelCallStmt(CompoundStmt *Body,
+                                               Expr *LaunchIdExpr);
 };
 
 } // namespace clang
diff --git a/clang/lib/AST/ComputeDependence.cpp b/clang/lib/AST/ComputeDependence.cpp
index 66fe5646b1864..34167eee8d8f2 100644
--- a/clang/lib/AST/ComputeDependence.cpp
+++ b/clang/lib/AST/ComputeDependence.cpp
@@ -16,7 +16,6 @@
 #include "clang/AST/ExprConcepts.h"
 #include "clang/AST/ExprObjC.h"
 #include "clang/AST/ExprOpenMP.h"
-#include "clang/AST/StmtSYCL.h"
 #include "clang/Basic/ExceptionSpecificationType.h"
 #include "llvm/ADT/ArrayRef.h"
 
diff --git a/clang/lib/CodeGen/CGStmt.cpp b/clang/lib/CodeGen/CGStmt.cpp
index 7b79e54132be8..ad31ecc75b01e 100644
--- a/clang/lib/CodeGen/CGStmt.cpp
+++ b/clang/lib/CodeGen/CGStmt.cpp
@@ -100,6 +100,7 @@ void CodeGenFunction::EmitStmt(const Stmt *S, ArrayRef<const Attr *> Attrs) {
   case Stmt::SEHExceptStmtClass:
   case Stmt::SEHFinallyStmtClass:
   case Stmt::MSDependentExistsStmtClass:
+  case Stmt::UnresolvedSYCLKernelCallStmtClass:
     llvm_unreachable("invalid statement class to emit generically");
   case Stmt::NullStmtClass:
   case Stmt::CompoundStmtClass:
@@ -114,7 +115,6 @@ void CodeGenFunction::EmitStmt(const Stmt *S, ArrayRef<const Attr *> Attrs) {
   case Stmt::DeferStmtClass:
   case Stmt::SEHLeaveStmtClass:
   case Stmt::SYCLKernelCallStmtClass:
-  case Stmt::UnresolvedSYCLKernelCallStmtClass:
     llvm_unreachable("should have emitted these statements as simple");
 
 #define STMT(Type, Base)
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 6c088280fefde..7badc3bc7abad 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -16353,10 +16353,15 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D,
 
   if (FD && !FD->isInvalidDecl() &&
       FD->hasAttr<SYCLKernelEntryPointAttr>() && FnBodyScope) {
-    // Building KernelLaunchIdExpr requires performing an unqualified lookup
-    // which can only be done correctly while the stack of parsing scopes is
-    // alive, so we do it here when we start parsing function body even if it is
-    // a templated function.
+    // An implicit call expression is synthesized for functions declared with
+    // the sycl_kernel_entry_point attribute. The call may resolve to a
+    // function template, a member function template, or a call operator
+    // of a variable template depending on the results of unqualified lookup
+    // for 'sycl_kernel_launch' from the beginning of the function body.
+    // Performing that lookup requires the stack of parsing scopes active
+    // when the definition is parsed and is thus done here; the result is
+    // cached in FunctionScopeInfo and used to synthesize the (possibly
+    // unresolved) call expression after the function body has been parsed.
     const auto *SKEPAttr = FD->getAttr<SYCLKernelEntryPointAttr>();
     if (!SKEPAttr->isInvalidAttr()) {
       ExprResult LaunchIdExpr =
@@ -16566,8 +16571,11 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, bool IsInstantiation,
       SKEPAttr->setInvalidAttr();
     }
 
-    // We don't need to build SYCLKernelCallStmt for template instantiations
-    // since it was already created by template instantiator.
+    // Build an unresolved SYCL kernel call statement for a function template,
+    // validate that a SYCL kernel call statement was instantiated for an
+    // (implicit or explicit) instantiation of a function template, or otherwise
+    // build a (resolved) SYCL kernel call statement for a non-templated
+    // function or an explicit specialization.
     if (Body && !SKEPAttr->isInvalidAttr()) {
       StmtResult SR;
       if (FD->isTemplated()) {
diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp
index 2a7bdde93f007..f0f39e99e8ae4 100644
--- a/clang/lib/Sema/SemaSYCL.cpp
+++ b/clang/lib/Sema/SemaSYCL.cpp
@@ -392,85 +392,82 @@ void SemaSYCL::CheckSYCLEntryPointFunctionDecl(FunctionDecl *FD) {
 
 ExprResult SemaSYCL::BuildSYCLKernelLaunchIdExpr(FunctionDecl *FD,
                                                  QualType KNT) {
+  // The current context must be the function definition context to ensure
+  // that name lookup is performed within the correct scope.
+  assert(SemaRef.CurContext == FD);
 
-  ASTContext &Ctx = SemaRef.getASTContext();
-  // Some routines need a valid source location to work correctly.
-  SourceLocation BodyLoc =
-      FD->getEndLoc().isValid() ? FD->getEndLoc() : FD->getLocation();
+  // An appropriate source location is required to emit diagnostics if
+  // lookup fails to produce an overload set. The desired location is the
+  // start of the function body, but that is not yet available since the
+  // body of the function has not yet been set when this function is called.
+  // The general location of the function is used instead.
+  SourceLocation Loc = FD->getLocation();
 
-  IdentifierInfo &LaunchFooName =
+  ASTContext &Ctx = SemaRef.getASTContext();
+  IdentifierInfo &SYCLKernelLaunchID =
       Ctx.Idents.get("sycl_kernel_launch", tok::TokenKind::identifier);
 
-  // Perform overload resolution for a call to an accessible (member) function
-  // template named 'sycl_kernel_launch' "from within the definition of
-  // FD where":
-  // - The kernel name type is passed as the first template argument.
-  // - Any remaining template parameters are deduced from the function
-  //   arguments or assigned by default template arguments.
-  // - 'this' is passed as the implicit function argument if 'FD' is a
-  //   non-static member function.
-  // - The name of the kernel, expressed as a string literal, is passed as the
-  //   first function argument.
-  // - The parameters of FD are forwarded as-if by 'std::forward()' as the
-  //   remaining explicit function arguments.
-  // - Any remaining function arguments are initialized by default arguments.
-  LookupResult Result(SemaRef, &LaunchFooName, BodyLoc,
+  // Perform ordinary name lookup for a function or variable template that
+  // accepts a single type template argument.
+  LookupResult Result(SemaRef, &SYCLKernelLaunchID, Loc,
                       Sema::LookupOrdinaryName);
-  CXXScopeSpec SS;
-  SemaRef.LookupTemplateName(Result, SemaRef.getCurScope(), SS,
-                             /*ObjectType=*/QualType(),
-                             /*EnteringContext=*/false, BodyLoc);
+  CXXScopeSpec EmptySS;
+  SemaRef.LookupTemplateName(Result, SemaRef.getCurScope(), EmptySS,
+                             /*ObjectType*/ QualType(),
+                             /*EnteringContext*/ false,
+                             Sema::TemplateNameIsRequired);
 
   if (Result.empty() || Result.isAmbiguous()) {
-    SemaRef.Diag(BodyLoc, SemaRef.getLangOpts().SYCLIsHost
-                              ? diag::err_sycl_host_no_launch_function
-                              : diag::warn_sycl_device_no_host_launch_function);
-    SemaRef.Diag(BodyLoc, diag::note_sycl_host_launch_function);
+    SemaRef.Diag(Loc, SemaRef.getLangOpts().SYCLIsHost
+                          ? diag::err_sycl_host_no_launch_function
+                          : diag::warn_sycl_device_no_host_launch_function);
+    SemaRef.Diag(Loc, diag::note_sycl_host_launch_function);
 
     return ExprError();
   }
 
-  TemplateArgumentListInfo TALI{BodyLoc, BodyLoc};
+  TemplateArgumentListInfo TALI{Loc, Loc};
   TemplateArgument KNTA = TemplateArgument(KNT);
   TemplateArgumentLoc TAL =
-      SemaRef.getTrivialTemplateArgumentLoc(KNTA, QualType(), BodyLoc);
+      SemaRef.getTrivialTemplateArgumentLoc(KNTA, QualType(), Loc);
   TALI.addArgument(TAL);
   ExprResult IdExpr;
-  if (SemaRef.isPotentialImplicitMemberAccess(SS, Result,
-                                              /*IsAddressOfOperand=*/false))
-    // BuildPossibleImplicitMemberExpr creates UnresolvedMemberExpr. Using it
-    // allows to pass implicit/explicit this argument automatically.
-    IdExpr = SemaRef.BuildPossibleImplicitMemberExpr(SS, BodyLoc, Result, &TALI,
+  if (SemaRef.isPotentialImplicitMemberAccess(EmptySS, Result,
+                                              /*IsAddressOfOperand*/ false))
+    // The lookup result allows for a possible implicit member access that
+    // would require an implicit or explicit 'this' argument.
+    IdExpr = SemaRef.BuildPossibleImplicitMemberExpr(EmptySS, SourceLocation(),
+                                                     Result, &TALI,
                                                      SemaRef.getCurScope());
   else
-    IdExpr = SemaRef.BuildTemplateIdExpr(SS, BodyLoc, Result,
-                                         /*RequiresADL=*/true, &TALI);
+    IdExpr = SemaRef.BuildTemplateIdExpr(EmptySS, SourceLocation(), Result,
+                                         /*RequiresADL*/ true, &TALI);
 
-  // Can happen if SKEP attributed function is a static member, but the launcher
-  // is a regular member. Perhaps emit a note saying that we're in host code
-  // synthesis.
+  // The resulting expression may be invalid if, for example, 'FD' is a
+  // non-static member function and sycl_kernel_launch lookup selects a
+  // member function (which would require a 'this' argument which is
+  // not available).
   if (IdExpr.isInvalid())
     return ExprError();
 
   return IdExpr;
 }
 
-StmtResult SemaSYCL::BuildUnresolvedSYCLKernelCallStmt(CompoundStmt *CS,
-                                                             Expr *IdExpr) {
-  return UnresolvedSYCLKernelCallStmt::Create(SemaRef.getASTContext(), CS,
-                                                    IdExpr);
-}
-
 namespace {
 
-void PrepareKernelArgumentsForKernelLaunch(SmallVectorImpl<Expr *> &Args,
-                                                  const SYCLKernelInfo *SKI,
-                                                  Sema &SemaRef,
-                                                  SourceLocation Loc) {
-  assert(SKI && "Need a kernel!");
-  ASTContext &Ctx = SemaRef.getASTContext();
+// Constructs the arguments to be passed for the SYCL kernel launch call.
+// The first argument is a string literal that contains the SYCL kernel
+// name. The remaining arguments are the parameters of 'FD'.
+void BuildSYCLKernelLaunchCallArgs(Sema &SemaRef, FunctionDecl *FD,
+                                   const SYCLKernelInfo *SKI,
+                                   SmallVectorImpl<Expr *> &Args,
+                                   SourceLocation Loc) {
+  // The current context must be the function definition context to ensure
+  // that parameter references occur within the correct scope.
+  assert(SemaRef.CurContext == FD);
 
   // Prepare a string literal that contains the kernel name.
+  ASTContext &Ctx = SemaRef.getASTContext();
   const std::string KernelName = SKI->GetKernelName();
   QualType KernelNameCharTy = Ctx.CharTy.withConst();
   llvm::APInt KernelNameSize(Ctx.getTypeSize(Ctx.getSizeType()),
@@ -482,30 +479,23 @@ void PrepareKernelArgumentsForKernelLaunch(SmallVectorImpl<Expr *> &Args,
                             /*Pascal*/ false, KernelNameArrayTy, Loc);
   Args.push_back(KernelNameExpr);
 
-  // Right now we simply forward the arguments of the skep-attributed function.
-  // With decomposition present there can be another logic.
-  // Make sure to use CurContext to avoid diagnostics that we're using a
-  // variable coming from another context. The function should be the same as in
-  // the kernel info though.
-  auto *FD = cast<FunctionDecl>(SemaRef.CurContext);
-  assert(declaresSameEntity(FD, SKI->getKernelEntryPointDecl()));
   for (ParmVarDecl *PVD : FD->parameters()) {
     QualType ParamType = PVD->getOriginalType().getNonReferenceType();
     Expr *DRE = SemaRef.BuildDeclRefExpr(PVD, ParamType, VK_LValue, Loc);
-    assert(DRE);
     Args.push_back(DRE);
   }
 }
 
-StmtResult BuildSYCLKernelLaunchStmt(Sema &SemaRef,
-                                            const SYCLKernelInfo *SKI,
-                                            Expr *IdExpr, SourceLocation Loc) {
+// Constructs the SYCL kernel launch call.
+StmtResult BuildSYCLKernelLaunchCallStmt(Sema &SemaRef, FunctionDecl *FD,
+                                         const SYCLKernelInfo *SKI,
+                                         Expr *IdExpr, SourceLocation Loc) {
   SmallVector<Stmt *> Stmts;
-  assert(SKI && "Need a Kernel!");
 
+  // IdExpr may be null if name lookup failed.
   if (IdExpr) {
     llvm::SmallVector<Expr *, 12> Args;
-    PrepareKernelArgumentsForKernelLaunch(Args, SKI, SemaRef, Loc);
+    BuildSYCLKernelLaunchCallArgs(SemaRef, FD, SKI, Args, Loc);
     ExprResult LaunchResult =
         SemaRef.BuildCallExpr(SemaRef.getCurScope(), IdExpr, Loc, Args, Loc);
     if (LaunchResult.isInvalid())
@@ -630,14 +620,20 @@ StmtResult SemaSYCL::BuildSYCLKernelCallStmt(FunctionDecl *FD,
       BuildSYCLKernelEntryPointOutline(SemaRef, FD, Body);
   assert(OFD);
 
-  // Build host kernel launch stmt.
-  SourceLocation BodyLoc =
-      FD->getEndLoc().isValid() ? FD->getEndLoc() : FD->getLocation();
-  StmtResult LaunchRes =
-      BuildSYCLKernelLaunchStmt(SemaRef, &SKI, LaunchIdExpr, BodyLoc);
+  // Build the host kernel launch statement. An appropriate source location
+  // is required to emit diagnostics.
+  SourceLocation Loc = Body->getLBracLoc();
+  StmtResult LaunchResult =
+      BuildSYCLKernelLaunchCallStmt(SemaRef, FD, &SKI, LaunchIdExpr, Loc);
 
   Stmt *NewBody =
-      new (getASTContext()) SYCLKernelCallStmt(Body, LaunchRes.get(), OFD);
+      new (getASTContext()) SYCLKernelCallStmt(Body, LaunchResult.get(), OFD);
 
   return NewBody;
 }
+
+StmtResult SemaSYCL::BuildUnresolvedSYCLKernelCallStmt(CompoundStmt *Body,
+                                                       Expr *LaunchIdExpr) {
+  return UnresolvedSYCLKernelCallStmt::Create(SemaRef.getASTContext(), Body,
+                                              LaunchIdExpr);
+}
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index c6efabdfadf43..6b47e5af8e834 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -13064,7 +13064,6 @@ StmtResult TreeTransform<Derived>::TransformUnresolvedSYCLKernelCallStmt(
     return StmtError();
 
   ExprResult IdExpr = getDerived().TransformExpr(S->getKernelLaunchIdExpr());
-
   if (IdExpr.isInvalid())
      return StmtError();
 
diff --git a/clang/test/ASTSYCL/ast-dump-sycl-kernel-call-stmt.cpp b/clang/test/ASTSYCL/ast-dump-sycl-kernel-call-stmt.cpp
index bf9e2e22d67d4..5eef5db069faf 100644
--- a/clang/test/ASTSYCL/ast-dump-sycl-kernel-call-stmt.cpp
+++ b/clang/test/ASTSYCL/ast-dump-sycl-kernel-call-stmt.cpp
@@ -34,7 +34,7 @@ template<int> struct K {
   void operator()(Ts...) const {}
 };
 
-template <typename KernelName, typename... Ts>
+template<typename KernelName, typename... Ts>
 void sycl_kernel_launch(const char *, Ts...) {}
 
 [[clang::sycl_kernel_entry_point(KN<1>)]]
@@ -373,18 +373,18 @@ void skep8(S8 k) {
 // CHECK:      | `-SYCLKernelEntryPointAttr {{.*}}
 
 class Handler {
-template <typename KernelName, typename... Ts>
-void sycl_kernel_launch(const char *, Ts...) {}
+  template <typename KNT, typename... Ts>
+  void sycl_kernel_launch(const char *, Ts...) {}
 public:
-template<typename KNT, typename KT>
-[[clang::sycl_kernel_entry_point(KNT)]]
-void skep9(KT k, int a, int b) {
-  k(a, b);
-}
+  template<typename KNT, typename KT>
+  [[clang::sycl_kernel_entry_point(KNT)]]
+  void skep9(KT k, int a, int b) {
+    k(a, b);
+  }
 };
 void foo() {
   Handler H;
-  H.skep9<KN<9>>([=](int a, int b){return a+b;}, 1, 2);
+  H.skep9<KN<9>>([=] (int a, int b) { return a+b; }, 1, 2);
 }
 
 // CHECK: | |-FunctionTemplateDecl {{.*}} skep9
diff --git a/clang/test/ASTSYCL/ast-dump-sycl-kernel-entry-point.cpp b/clang/test/ASTSYCL/ast-dump-sycl-kernel-entry-point.cpp
index 7645dd4216271..011f48e91c292 100644
--- a/clang/test/ASTSYCL/ast-dump-sycl-kernel-entry-point.cpp
+++ b/clang/test/ASTSYCL/ast-dump-sycl-kernel-entry-point.cpp
@@ -28,8 +28,8 @@
 // A unique kernel name type is required for each declared kernel entry point.
 template<int, int=0> struct KN;
 
-template <typename KernelName, typename... Tys>
-void sycl_kernel_launch(const char *, Tys &&...Args) {}
+template<typename KernelName, typename... Ts>
+void sycl_kernel_launch(const char *, Ts... Args) {}
 
 [[clang::sycl_kernel_entry_point(KN<1>)]]
 void skep1() {
diff --git a/clang/test/AST/ast-print-sycl-kernel-call.cpp b/clang/test/ASTSYCL/ast-print-sycl-kernel-call.cpp
similarity index 61%
rename from clang/test/AST/ast-print-sycl-kernel-call.cpp
rename to clang/test/ASTSYCL/ast-print-sycl-kernel-call.cpp
index 64c6624b768c9..5adaa367ed9c1 100644
--- a/clang/test/AST/ast-print-sycl-kernel-call.cpp
+++ b/clang/test/ASTSYCL/ast-print-sycl-kernel-call.cpp
@@ -6,17 +6,20 @@ struct sycl_kernel_launcher {
   void sycl_kernel_launch(const char *, Ts...) {}
 
   template<typename KernelName, typename KernelType>
-  void kernel_entry_point(KernelType kernel) {
+  [[clang::sycl_kernel_entry_point(KernelName)]]
+  void sycl_kernel_entry_point(KernelType kernel) {
     kernel();
   }
-// CHECK:      template <typename KernelName, typename KernelType> void kernel_entry_point(KernelType kernel) {
+};
+// CHECK:      template <typename KernelName, typename KernelType> void sycl_kernel_entry_point(KernelType kernel)
+// CHECK-NEXT: {
 // CHECK-NEXT:     kernel();
 // CHECK-NEXT: }
-// CHECK:      template<> void kernel_entry_point<KN, (lambda at {{.*}})>((lambda at {{.*}}) kernel) {
+// CHECK:      template<> void sycl_kernel_entry_point<KN, (lambda at {{.*}})>((lambda at {{.*}}) kernel)
+// CHECK-NEXT: {
 // CHECK-NEXT:     kernel();
 // CHECK-NEXT: }
-};
 
 void f(sycl_kernel_launcher skl) {
-  skl.kernel_entry_point<struct KN>([]{});
+  skl.sycl_kernel_entry_point<struct KN>([]{});
 }
diff --git a/clang/test/CodeGenSYCL/kernel-caller-entry-point.cpp b/clang/test/CodeGenSYCL/kernel-caller-entry-point.cpp
index d2b8addae3ced..596b5316e6330 100644
--- a/clang/test/CodeGenSYCL/kernel-caller-entry-point.cpp
+++ b/clang/test/CodeGenSYCL/kernel-caller-entry-point.cpp
@@ -2,36 +2,36 @@
 // RUN: %clang_cc1 -fsycl-is-device -emit-llvm -aux-triple x86_64-unknown-linux-gnu -triple amdgcn-amd-amdhsa -std=c++17 %s -o - | FileCheck --check-prefixes=CHECK-DEVICE,CHECK-AMDGCN %s
 // RUN: %clang_cc1 -fsycl-is-device -emit-llvm -aux-triple x86_64-unknown-linux-gnu -triple nvptx-nvidia-cuda -std=c++17 %s -o - | FileCheck --check-prefixes=CHECK-DEVICE,CHECK-NVPTX %s
 // RUN: %clang_cc1 -fsycl-is-device -emit-llvm -aux-triple x86_64-unknown-linux-gnu -triple nvptx64-nvidia-cuda -std=c++17 %s -o - | FileCheck --check-prefixes=CHECK-DEVICE,CHECK-NVPTX %s
-// RUN: %clang_cc1 -fsycl-is-device -emit-llvm -aux-triple x86_64-unknown-linux-gnu -triple spir-unknown-unknown -std=c++17 %s -o - | FileCheck --check-prefixes=CHECK-DEVICE,CHECK-SPIR %s
-// RUN: %clang_cc1 -fsycl-is-device -emit-llvm -aux-triple x86_64-unknown-linux-gnu -triple spir64-unknown-unknown -std=c++17 %s -o - | FileCheck --check-prefixes=CHECK-DEVICE,CHECK-SPIR %s
-// RUN: %clang_cc1 -fsycl-is-device -emit-llvm -aux-triple x86_64-unknown-linux-gnu -triple spirv32-unknown-unknown -std=c++17 %s -o - | FileCheck --check-prefixes=CHECK-DEVICE,CHECK-SPIR %s
-// RUN: %clang_cc1 -fsycl-is-device -emit-llvm -aux-triple x86_64-unknown-linux-gnu -triple spirv64-unknown-unknown -std=c++17 %s -o - | FileCheck --check-prefixes=CHECK-DEVICE,CHECK-SPIR %s
+// RUN: %clang_cc1 -fsycl-is-device -emit-llvm -aux-triple x86_64-unknown-linux-gnu -triple spir-unknown-unknown -std=c++17 %s -o - | FileCheck --check-prefixes=CHECK-DEVICE,CHECK-SPIR,CHECK-SPIRNV %s
+// RUN: %clang_cc1 -fsycl-is-device -emit-llvm -aux-triple x86_64-unknown-linux-gnu -triple spir64-unknown-unknown -std=c++17 %s -o - | FileCheck --check-prefixes=CHECK-DEVICE,CHECK-SPIR,CHECK-SPIRNV %s
+// RUN: %clang_cc1 -fsycl-is-device -emit-llvm -aux-triple x86_64-unknown-linux-gnu -triple spirv32-unknown-unknown -std=c++17 %s -o - | FileCheck --check-prefixes=CHECK-DEVICE,CHECK-SPIR,CHECK-SPIRV %s
+// RUN: %clang_cc1 -fsycl-is-device -emit-llvm -aux-triple x86_64-unknown-linux-gnu -triple spirv64-unknown-unknown -std=c++17 %s -o - | FileCheck --check-prefixes=CHECK-DEVICE,CHECK-SPIR,CHECK-SPIRV %s
 // RUN: %clang_cc1 -fsycl-is-host -emit-llvm -triple x86_64-pc-windows-msvc -std=c++17 %s -o - | FileCheck --check-prefixes=CHECK-HOST,CHECK-HOST-WINDOWS %s
 // RUN: %clang_cc1 -fsycl-is-device -emit-llvm -aux-triple x86_64-pc-windows-msvc -triple amdgcn-amd-amdhsa -std=c++17 %s -o - | FileCheck --check-prefixes=CHECK-DEVICE,CHECK-AMDGCN %s
 // RUN: %clang_cc1 -fsycl-is-device -emit-llvm -aux-triple x86_64-pc-windows-msvc -triple nvptx-nvidia-cuda -std=c++17 %s -o - | FileCheck --check-prefixes=CHECK-DEVICE,CHECK-NVPTX %s
 // RUN: %clang_cc1 -fsycl-is-device -emit-llvm -aux-triple x86_64-pc-windows-msvc -triple nvptx64-nvidia-cuda -std=c++17 %s -o - | FileCheck --check-prefixes=CHECK-DEVICE,CHECK-NVPTX %s
-// RUN: %clang_cc1 -fsycl-is-device -emit-llvm -aux-triple x86_64-pc-windows-msvc -triple spir-unknown-unknown -std=c++17 %s -o - | FileCheck --check-prefixes=CHECK-DEVICE,CHECK-SPIR %s
-// RUN: %clang_cc1 -fsycl-is-device -emit-llvm -aux-triple x86_64-pc-windows-msvc -triple spir64-unknown-unknown -std=c++17 %s -o - | FileCheck --check-prefixes=CHECK-DEVICE,CHECK-SPIR %s
-// RUN: %clang_cc1 -fsycl-is-device -emit-llvm -aux-triple x86_64-pc-windows-msvc -triple spirv32-unknown-unknown -std=c++17 %s -o - | FileCheck --check-prefixes=CHECK-DEVICE,CHECK-SPIR %s
-// RUN: %clang_cc1 -fsycl-is-device -emit-llvm -aux-triple x86_64-pc-windows-msvc -triple spirv64-unknown-unknown -std=c++17 %s -o - | FileCheck --check-prefixes=CHECK-DEVICE,CHECK-SPIR %s
+// RUN: %clang_cc1 -fsycl-is-device -emit-llvm -aux-triple x86_64-pc-windows-msvc -triple spir-unknown-unknown -std=c++17 %s -o - | FileCheck --check-prefixes=CHECK-DEVICE,CHECK-SPIR,CHECK-SPIRNV %s
+// RUN: %clang_cc1 -fsycl-is-device -emit-llvm -aux-triple x86_64-pc-windows-msvc -triple spir64-unknown-unknown -std=c++17 %s -o - | FileCheck --check-prefixes=CHECK-DEVICE,CHECK-SPIR,CHECK-SPIRNV %s
+// RUN: %clang_cc1 -fsycl-is-device -emit-llvm -aux-triple x86_64-pc-windows-msvc -triple spirv32-unknown-unknown -std=c++17 %s -o - | FileCheck --check-prefixes=CHECK-DEVICE,CHECK-SPIR,CHECK-SPIRV %s
+// RUN: %clang_cc1 -fsycl-is-device -emit-llvm -aux-triple x86_64-pc-windows-msvc -triple spirv64-unknown-unknown -std=c++17 %s -o - | FileCheck --check-prefixes=CHECK-DEVICE,CHECK-SPIR,CHECK-SPIRV %s
 // RUN: %clang_cc1 -fsycl-is-host -emit-llvm -triple x86_64-uefi -std=c++17 %s -o - | FileCheck --check-prefixes=CHECK-HOST,CHECK-HOST-WINDOWS %s
 // RUN: %clang_cc1 -fsycl-is-device -emit-llvm -aux-triple x86_64-uefi -triple amdgcn-amd-amdhsa -std=c++17 %s -o - | FileCheck --check-prefixes=CHECK-DEVICE,CHECK-AMDGCN %s
 // RUN: %clang_cc1 -fsycl-is-device -emit-llvm -aux-triple x86_64-uefi -triple nvptx-nvidia-cuda -std=c++17 %s -o - | FileCheck --check-prefixes=CHECK-DEVICE,CHECK-NVPTX %s
 // RUN: %clang_cc1 -fsycl-is-device -emit-llvm -aux-triple x86_64-uefi -triple nvptx64-nvidia-cuda -std=c++17 %s -o - | FileCheck --check-prefixes=CHECK-DEVICE,CHECK-NVPTX %s
-// RUN: %clang_cc1 -fsycl-is-device -emit-llvm -aux-triple x86_64-uefi -triple spir-unknown-unknown -std=c++17 %s -o - | FileCheck --check-prefixes=CHECK-DEVICE,CHECK-SPIR %s
-// RUN: %clang_cc1 -fsycl-is-device -emit-llvm -aux-triple x86_64-uefi -triple spir64-unknown-unknown -std=c++17 %s -o - | FileCheck --check-prefixes=CHECK-DEVICE,CHECK-SPIR %s
-// RUN: %clang_cc1 -fsycl-is-device -emit-llvm -aux-triple x86_64-uefi -triple spirv32-unknown-unknown -std=c++17 %s -o - | FileCheck --check-prefixes=CHECK-DEVICE,CHECK-SPIR %s
-// RUN: %clang_cc1 -fsycl-is-device -emit-llvm -aux-triple x86_64-uefi -triple spirv64-unknown-unknown -std=c++17 %s -o - | FileCheck --check-prefixes=CHECK-DEVICE,CHECK-SPIR %s
+// RUN: %clang_cc1 -fsycl-is-device -emit-llvm -aux-triple x86_64-uefi -triple spir-unknown-unknown -std=c++17 %s -o - | FileCheck --check-prefixes=CHECK-DEVICE,CHECK-SPIR,CHECK-SPIRNV %s
+// RUN: %clang_cc1 -fsycl-is-device -emit-llvm -aux-triple x86_64-uefi -triple spir64-unknown-unknown -std=c++17 %s -o - | FileCheck --check-prefixes=CHECK-DEVICE,CHECK-SPIR,CHECK-SPIRNV %s
+// RUN: %clang_cc1 -fsycl-is-device -emit-llvm -aux-triple x86_64-uefi -triple spirv32-unknown-unknown -std=c++17 %s -o - | FileCheck --check-prefixes=CHECK-DEVICE,CHECK-SPIR,CHECK-SPIRV %s
+// RUN: %clang_cc1 -fsycl-is-device -emit-llvm -aux-triple x86_64-uefi -triple spirv64-unknown-unknown -std=c++17 %s -o - | FileCheck --check-prefixes=CHECK-DEVICE,CHECK-SPIR,CHECK-SPIRV %s
 
-// Test the generation of SYCL kernel caller functions. These functions are
-// generated from functions declared with the sycl_kernel_entry_point attribute
-// and emited during device compilation.
-// Test the generation of SYCL kernel launch statements during host compilation.
-// These statements are calls to sycl_enqueus_kernel_launch functions or class
-// members in case skep-attributed functions are also members of the same class.
+// Test code generation for functions declared with the sycl_kernel_entry_point
+// attribute. During host compilation, the bodies of such functions are replaced
+// with calls to a function template or variable template (with suitable call
+// operator) named sycl_kernel_launch. During device compilation, the bodies of
+// these functions are used to generate offload kernel entry points (SYCL kernel
+// caller functions).
 
-template <typename KernelName, typename KernelObj>
-void sycl_kernel_launch(const char *, KernelObj) {}
+template <typename KernelName, typename... Ts>
+void sycl_kernel_launch(const char *, Ts...) {}
 
 struct single_purpose_kernel_name;
 struct single_purpose_kernel {
@@ -52,32 +52,20 @@ void kernel_single_task(KernelType kernelFunc) {
 // Exercise code gen with kernel name types named with esoteric characters.
 struct \u03b4\u03c4\u03c7; // Delta Tau Chi (δτχ)
 
-class Handler {
-template <typename KernelName, typename... Ts>
-void sycl_kernel_launch(const char *, Ts...) {}
+class handler {
+  template <typename KernelName, typename... Ts>
+  void sycl_kernel_launch(const char *, Ts...) {}
 public:
-template<typename KNT, typename KT>
-[[clang::sycl_kernel_entry_point(KNT)]]
-void skep(KT k, int a, int b) {
-  k(a, b);
-}
+  template <typename KernelName, typename KernelType>
+  [[clang::sycl_kernel_entry_point(KernelName)]]
+  void kernel_entry_point(KernelType k, int a, int b) {
+    k(a, b);
+  }
 };
 
-struct auto_name;
-
-template <typename KernelName, typename KernelType>
-[[clang::sycl_kernel_entry_point(KernelName)]]
-void __kernel_single_task(const KernelType KernelFunc) {
-  KernelFunc();
-}
-
-template <typename KernelType, typename KernelName = auto_name>
-void pf(KernelType K) {
-  __kernel_single_task<KernelName>(K);
-}
-struct DCopyable {
+struct copyable {
   int i;
-  ~DCopyable();
+  ~copyable();
 };
 
 int main() {
@@ -87,11 +75,9 @@ int main() {
   auto lambda = [=](auto) { (void) capture; };
   kernel_single_task<decltype(lambda)>(lambda);
   kernel_single_task<\u03b4\u03c4\u03c7>([](int){});
-  Handler H;
-  H.skep<class notaverygoodkernelname>([=](int a, int b){return a+b;}, 1, 2);
-
-  DCopyable b;
-  pf([b](){});
+  handler h;
+  copyable c{42};
+  h.kernel_entry_point<struct KN>([=] (int a, int b) { return c.i + a + b; }, 1, 2);
 }
 
 // Verify that SYCL kernel caller functions are not emitted during host
@@ -100,12 +86,14 @@ int main() {
 // CHECK-HOST-NOT: define {{.*}} @_ZTS26single_purpose_kernel_name
 // CHECK-HOST-NOT: define {{.*}} @_ZTSZ4mainEUlT_E_
 // CHECK-HOST-NOT: define {{.*}} @"_ZTS6\CE\B4\CF\84\CF\87"
+// CHECK-HOST-NOT: define {{.*}} @_ZTSZ4mainE2KN
 
 // Verify that sycl_kernel_entry_point attributed functions are not emitted
 // during device compilation.
 //
 // CHECK-DEVICE-NOT: single_purpose_kernel_task
 // CHECK-DEVICE-NOT: kernel_single_task
+// CHECK-DEVICE-NOT: kernel_entry_point
 
 // Verify that kernel launch code is generated for sycl_kernel_entry_point
 // attributed functions during host compilation.
@@ -118,7 +106,7 @@ int main() {
 // CHECK-HOST-LINUX-NEXT: entry:
 // CHECK-HOST-LINUX-NEXT:   %kernelFunc = alloca %struct.single_purpose_kernel, align 1
 // CHECK-HOST-LINUX-NEXT:   %agg.tmp = alloca %struct.single_purpose_kernel, align 1
-// CHECK-HOST-LINUX-NEXT:   call void @_Z18sycl_kernel_launchI26single_purpose_kernel_name21single_purpose_kernelEvPKcT0_(ptr noundef @.str)
+// CHECK-HOST-LINUX-NEXT:   call void @_Z18sycl_kernel_launchI26single_purpose_kernel_nameJ21single_purpose_kernelEEvPKcDpT0_(ptr noundef @.str)
 // CHECK-HOST-LINUX-NEXT:   ret void
 // CHECK-HOST-LINUX-NEXT: }
 //
@@ -131,7 +119,7 @@ int main() {
 // CHECK-HOST-LINUX-NEXT:   call void @llvm.memcpy.p0.p0.i64(ptr align 4 %agg.tmp, ptr align 4 %kernelFunc, i64 4, i1 false)
 // CHECK-HOST-LINUX-NEXT:   %coerce.dive1 = getelementptr inbounds nuw %class.anon, ptr %agg.tmp, i32 0, i32 0
 // CHECK-HOST-LINUX-NEXT:   %0 = load i32, ptr %coerce.dive1, align 4
-// CHECK-HOST-LINUX-NEXT:   call void @_Z18sycl_kernel_launchIZ4mainEUlT_E_S1_EvPKcT0_(ptr noundef @.str.1, i32 %0)
+// CHECK-HOST-LINUX-NEXT:   call void @_Z18sycl_kernel_launchIZ4mainEUlT_E_JS1_EEvPKcDpT0_(ptr noundef @.str.1, i32 %0)
 // CHECK-HOST-LINUX-NEXT:   ret void
 // CHECK-HOST-LINUX-NEXT: }
 //
@@ -139,35 +127,28 @@ int main() {
 // CHECK-HOST-LINUX-NEXT: entry:
 // CHECK-HOST-LINUX-NEXT:   %kernelFunc = alloca %class.anon.0, align 1
 // CHECK-HOST-LINUX-NEXT:   %agg.tmp = alloca %class.anon.0, align 1
-// CHECK-HOST-LINUX-NEXT:   call void @"_Z18sycl_kernel_launchI6\CE\B4\CF\84\CF\87Z4mainEUliE_EvPKcT0_"(ptr noundef @.str.2)
+// CHECK-HOST-LINUX-NEXT:   call void @"_Z18sycl_kernel_launchI6\CE\B4\CF\84\CF\87JZ4mainEUliE_EEvPKcDpT0_"(ptr noundef @.str.2)
 // CHECK-HOST-LINUX-NEXT:   ret void
 // CHECK-HOST-LINUX-NEXT: }
 
-// CHECK-HOST-LINUX: define internal void @_ZN7Handler4skepIZ4mainE22notaverygoodkernelnameZ4mainEUliiE_EEvT0_ii(ptr noundef nonnull align 1 dereferenceable(1) %this, i32 noundef %a, i32 noundef %b) #0 align 2 {
+
+// CHECK-HOST-LINUX:      define internal void @_ZN7handler18kernel_entry_pointIZ4mainE2KNZ4mainEUliiE_EEvT0_ii(ptr noundef nonnull align 1 dereferenceable(1) %this, ptr noundef %k, i32 noundef %a, i32 noundef %b) #{{[0-9]+}} align 2 {
 // CHECK-HOST-LINUX-NEXT: entry:
-// CHECK-HOST-LINUX-NEXT:   %k = alloca %class.anon.1, align 1
 // CHECK-HOST-LINUX-NEXT:   %this.addr = alloca ptr, align 8
+// CHECK-HOST-LINUX-NEXT:   %k.indirect_addr = alloca ptr, align 8
 // CHECK-HOST-LINUX-NEXT:   %a.addr = alloca i32, align 4
 // CHECK-HOST-LINUX-NEXT:   %b.addr = alloca i32, align 4
-// CHECK-HOST-LINUX-NEXT:   %agg.tmp = alloca %class.anon.1, align 1
+// CHECK-HOST-LINUX-NEXT:   %agg.tmp = alloca %class.anon.1, align 4
 // CHECK-HOST-LINUX-NEXT:   store ptr %this, ptr %this.addr, align 8
+// CHECK-HOST-LINUX-NEXT:   store ptr %k, ptr %k.indirect_addr, align 8
 // CHECK-HOST-LINUX-NEXT:   store i32 %a, ptr %a.addr, align 4
 // CHECK-HOST-LINUX-NEXT:   store i32 %b, ptr %b.addr, align 4
 // CHECK-HOST-LINUX-NEXT:   %this1 = load ptr, ptr %this.addr, align 8
+// CHECK-HOST-LINUX-NEXT:   call void @llvm.memcpy.p0.p0.i64(ptr align 4 %agg.tmp, ptr align 4 %k, i64 4, i1 false)
 // CHECK-HOST-LINUX-NEXT:   %0 = load i32, ptr %a.addr, align 4
 // CHECK-HOST-LINUX-NEXT:   %1 = load i32, ptr %b.addr, align 4
-// CHECK-HOST-LINUX-NEXT:   call void @_ZN7Handler18sycl_kernel_launchIZ4mainE22notaverygoodkernelnameJZ4mainEUliiE_iiEEEvPKcDpT0_(ptr noundef nonnull align 1 dereferenceable(1) %this1, ptr noundef @.str.3, i32 noundef %0, i32 noundef %1)
-// CHECK-HOST-LINUX-NEXT:   ret void
-// CHECK-HOST-LINUX-NEXT: }
-
-// CHECK-HOST-LINUX: define internal void @_Z20__kernel_single_taskI9auto_nameZ4mainEUlvE_EvT0_(ptr noundef %KernelFunc)
-// CHECK-HOST-LINUX-NEXT: entry:
-// CHECK-HOST-LINUX-NEXT:   %KernelFunc.indirect_addr = alloca ptr, align 8
-// CHECK-HOST-LINUX-NEXT:   %agg.tmp = alloca %class.anon.3, align 4
-// CHECK-HOST-LINUX-NEXT:   store ptr %KernelFunc, ptr %KernelFunc.indirect_addr, align 8
-// CHECK-HOST-LINUX-NEXT:   call void @llvm.memcpy.p0.p0.i64(ptr align 4 %agg.tmp, ptr align 4 %KernelFunc, i64 4, i1 false)
-// CHECK-HOST-LINUX-NEXT:   call void @_Z18sycl_kernel_launchI9auto_nameZ4mainEUlvE_EvPKcT0_(ptr noundef @.str.4, ptr noundef %agg.tmp)
-// CHECK-HOST-LINUX-NEXT:   call void @_ZZ4mainENUlvE_D1Ev(ptr noundef nonnull align 4 dereferenceable(4) %agg.tmp) #4
+// CHECK-HOST-LINUX-NEXT:   call void @_ZN7handler18sycl_kernel_launchIZ4mainE2KNJZ4mainEUliiE_iiEEEvPKcDpT0_(ptr noundef nonnull align 1 dereferenceable(1) %this1, ptr noundef @.str.3, ptr noundef %agg.tmp, i32 noundef %0, i32 noundef %1)
+// CHECK-HOST-LINUX-NEXT:   call void @_ZZ4mainENUliiE_D1Ev(ptr noundef nonnull align 4 dereferenceable(4) %agg.tmp) #{{[0-9]+}}
 // CHECK-HOST-LINUX-NEXT:   ret void
 // CHECK-HOST-LINUX-NEXT: }
 
@@ -209,40 +190,28 @@ int main() {
 // CHECK-HOST-WINDOWS-NEXT:   ret void
 // CHECK-HOST-WINDOWS-NEXT: }
 
-// CHECK-HOST-WINDOWS: define internal void @"??$skep at Vnotaverygoodkernelname@?1??main@@9 at V<lambda_3>@?0??2 at 9@@Handler@@QEAAXV<lambda_3>@?0??main@@9 at HH@Z"(ptr noundef nonnull align 1 dereferenceable(1) %this, i8 %k.coerce, i32 noundef %a, i32 noundef %b) #0 align 2 {
+// CHECK-HOST-WINDOWS:      define internal void @"??$kernel_entry_point at UKN@?1??main@@9 at V<lambda_3>@?0??2 at 9@@handler@@QEAAXV<lambda_3>@?0??main@@9 at HH@Z"(ptr noundef nonnull align 1 dereferenceable(1) %this, i32 %k.coerce, i32 noundef %a, i32 noundef %b) #{{[0-9]+}} align 2
 // CHECK-HOST-WINDOWS-NEXT: entry:
-// CHECK-HOST-WINDOWS-NEXT:   %k = alloca %class.anon.1, align 1
+// CHECK-HOST-WINDOWS-NEXT:   %k = alloca %class.anon.1, align 4
 // CHECK-HOST-WINDOWS-NEXT:   %b.addr = alloca i32, align 4
 // CHECK-HOST-WINDOWS-NEXT:   %a.addr = alloca i32, align 4
 // CHECK-HOST-WINDOWS-NEXT:   %this.addr = alloca ptr, align 8
-// CHECK-HOST-WINDOWS-NEXT:   %agg.tmp = alloca %class.anon.1, align 1
+// CHECK-HOST-WINDOWS-NEXT:   %agg.tmp = alloca %class.anon.1, align 4
 // CHECK-HOST-WINDOWS-NEXT:   %coerce.dive = getelementptr inbounds nuw %class.anon.1, ptr %k, i32 0, i32 0
-// CHECK-HOST-WINDOWS-NEXT:   store i8 %k.coerce, ptr %coerce.dive, align 1
+// CHECK-HOST-WINDOWS-NEXT:   %coerce.dive1 = getelementptr inbounds nuw %struct.copyable, ptr %coerce.dive, i32 0, i32 0
+// CHECK-HOST-WINDOWS-NEXT:   store i32 %k.coerce, ptr %coerce.dive1, align 4
 // CHECK-HOST-WINDOWS-NEXT:   store i32 %b, ptr %b.addr, align 4
 // CHECK-HOST-WINDOWS-NEXT:   store i32 %a, ptr %a.addr, align 4
 // CHECK-HOST-WINDOWS-NEXT:   store ptr %this, ptr %this.addr, align 8
-// CHECK-HOST-WINDOWS-NEXT:   %this1 = load ptr, ptr %this.addr, align 8
+// CHECK-HOST-WINDOWS-NEXT:   %this2 = load ptr, ptr %this.addr, align 8
 // CHECK-HOST-WINDOWS-NEXT:   %0 = load i32, ptr %b.addr, align 4
 // CHECK-HOST-WINDOWS-NEXT:   %1 = load i32, ptr %a.addr, align 4
-// CHECK-HOST-WINDOWS-NEXT:   %coerce.dive2 = getelementptr inbounds nuw %class.anon.1, ptr %agg.tmp, i32 0, i32 0
-// CHECK-HOST-WINDOWS-NEXT:   %2 = load i8, ptr %coerce.dive2, align 1
-// CHECK-HOST-WINDOWS-NEXT:   call void @"??$sycl_kernel_launch at Vnotaverygoodkernelname@?1??main@@9 at V<lambda_3>@?0??2 at 9@HH at Handler@@AEAAXPEBDV<lambda_3>@?0??main@@9 at HH@Z"(ptr noundef nonnull align 1 dereferenceable(1) %this1, ptr noundef @"??_C at _0CE@NJIGCEIA at _ZTSZ4mainE22notaverygoodkerneln@", i8 %2, i32 noundef %1, i32 noundef %0)
-// CHECK-HOST-WINDOWS-NEXT:   ret void
-// CHECK-HOST-WINDOWS-NEXT: }
-
-// CHECK-HOST-WINDOWS: define internal void @"??$__kernel_single_task at Uauto_name@@V<lambda_4>@?0??main@@9@@@YAXV<lambda_4>@?0??main@@9@@Z"(i32 %KernelFunc.coerce)
-// CHECK-HOST-WINDOWS-NEXT: entry:
-// CHECK-HOST-WINDOWS-NEXT:   %KernelFunc = alloca %class.anon.3, align 4
-// CHECK-HOST-WINDOWS-NEXT:   %agg.tmp = alloca %class.anon.3, align 4
-// CHECK-HOST-WINDOWS-NEXT:   %coerce.dive = getelementptr inbounds nuw %class.anon.3, ptr %KernelFunc, i32 0, i32 0
-// CHECK-HOST-WINDOWS-NEXT:   %coerce.dive1 = getelementptr inbounds nuw %struct.DCopyable, ptr %coerce.dive, i32 0, i32 0
-// CHECK-HOST-WINDOWS-NEXT:   store i32 %KernelFunc.coerce, ptr %coerce.dive1, align 4
-// CHECK-HOST-WINDOWS-NEXT:   call void @llvm.memcpy.p0.p0.i64(ptr align 4 %agg.tmp, ptr align 4 %KernelFunc, i64 4, i1 false)
-// CHECK-HOST-WINDOWS-NEXT:   %coerce.dive2 = getelementptr inbounds nuw %class.anon.3, ptr %agg.tmp, i32 0, i32 0
-// CHECK-HOST-WINDOWS-NEXT:   %coerce.dive3 = getelementptr inbounds nuw %struct.DCopyable, ptr %coerce.dive2, i32 0, i32 0
-// CHECK-HOST-WINDOWS-NEXT:   %0 = load i32, ptr %coerce.dive3, align 4
-// CHECK-HOST-WINDOWS-NEXT:   call void @"??$sycl_kernel_launch at Uauto_name@@V<lambda_4>@?0??main@@9@@@YAXPEBDV<lambda_4>@?0??main@@9@@Z"(ptr noundef @"??_C at _0P@HMAAEHI at _ZTS9auto_name?$AA@", i32 %0)
-// CHECK-HOST-WINDOWS-NEXT:   call void @"??1<lambda_4>@?0??main@@9 at QEAA@XZ"(ptr noundef nonnull align 4 dereferenceable(4) %KernelFunc)
+// CHECK-HOST-WINDOWS-NEXT:   call void @llvm.memcpy.p0.p0.i64(ptr align 4 %agg.tmp, ptr align 4 %k, i64 4, i1 false)
+// CHECK-HOST-WINDOWS-NEXT:   %coerce.dive3 = getelementptr inbounds nuw %class.anon.1, ptr %agg.tmp, i32 0, i32 0
+// CHECK-HOST-WINDOWS-NEXT:   %coerce.dive4 = getelementptr inbounds nuw %struct.copyable, ptr %coerce.dive3, i32 0, i32 0
+// CHECK-HOST-WINDOWS-NEXT:   %2 = load i32, ptr %coerce.dive4, align 4
+// CHECK-HOST-WINDOWS-NEXT:   call void @"??$sycl_kernel_launch at UKN@?1??main@@9 at V<lambda_3>@?0??2 at 9@HH at handler@@AEAAXPEBDV<lambda_3>@?0??main@@9 at HH@Z"(ptr noundef nonnull align 1 dereferenceable(1) %this2, ptr noundef @"??_C at _0P@DLGHPODL at _ZTSZ4mainE2KN?$AA@", i32 %2, i32 noundef %1, i32 noundef %0)
+// CHECK-HOST-WINDOWS-NEXT:   call void @"??1<lambda_3>@?0??main@@9 at QEAA@XZ"(ptr noundef nonnull align 4 dereferenceable(4) %k) #{{[0-9]+}}
 // CHECK-HOST-WINDOWS-NEXT:   ret void
 // CHECK-HOST-WINDOWS-NEXT: }
 
@@ -364,6 +333,84 @@ int main() {
 // CHECK-SPIR-NEXT:   }
 // CHECK-SPIR:        define internal spir_func void @_ZZ4mainENKUliE_clEi
 
+// IR for the SYCL kernel caller function generated for
+// handler::kernel_entry_point with main::KN as the SYCL kernel name type.
+//
+// CHECK-AMDGCN:      Function Attrs: convergent mustprogress noinline norecurse nounwind optnone
+// CHECK-AMDGCN-NEXT: define dso_local amdgpu_kernel void @_ZTSZ4mainE2KN
+// CHECK-AMDGCN-SAME:   (i32 %k.coerce, i32 noundef %a, i32 noundef %b) #[[AMDGCN_ATTR0]] {
+// CHECK-AMDGCN-NEXT: entry:
+// CHECK-AMDGCN-NEXT:   %k = alloca %class.anon.1, align 4, addrspace(5)
+// CHECK-AMDGCN-NEXT:   %a.addr = alloca i32, align 4, addrspace(5)
+// CHECK-AMDGCN-NEXT:   %b.addr = alloca i32, align 4, addrspace(5)
+// CHECK-AMDGCN-NEXT:   %k2 = addrspacecast ptr addrspace(5) %k to ptr
+// CHECK-AMDGCN-NEXT:   %a.addr.ascast = addrspacecast ptr addrspace(5) %a.addr to ptr
+// CHECK-AMDGCN-NEXT:   %b.addr.ascast = addrspacecast ptr addrspace(5) %b.addr to ptr
+// CHECK-AMDGCN-NEXT:   %coerce.dive = getelementptr inbounds nuw %class.anon.1, ptr %k2, i32 0, i32 0
+// CHECK-AMDGCN-NEXT:   %coerce.dive1 = getelementptr inbounds nuw %struct.copyable, ptr %coerce.dive, i32 0, i32 0
+// CHECK-AMDGCN-NEXT:   store i32 %k.coerce, ptr %coerce.dive1, align 4
+// CHECK-AMDGCN-NEXT:   store i32 %a, ptr %a.addr.ascast, align 4
+// CHECK-AMDGCN-NEXT:   store i32 %b, ptr %b.addr.ascast, align 4
+// CHECK-AMDGCN-NEXT:   %0 = load i32, ptr %a.addr.ascast, align 4
+// CHECK-AMDGCN-NEXT:   %1 = load i32, ptr %b.addr.ascast, align 4
+// CHECK-AMDGCN-NEXT:   %call = call noundef i32 @_ZZ4mainENKUliiE_clEii
+// CHECK-AMDGCN-SAME:     (ptr noundef nonnull align 4 dereferenceable(4) %k2, i32 noundef %0, i32 noundef %1) #[[AMDGCN_ATTR1:[0-9]+]]
+// CHECK-AMDGCN-NEXT:   ret void
+// CHECK-AMDGCN-NEXT: }
+//
+// CHECK-NVPTX:       Function Attrs: convergent mustprogress noinline norecurse nounwind optnone
+// CHECK-NVPTX-NEXT:  define dso_local ptx_kernel void @_ZTSZ4mainE2KN
+// CHECK-NVPTX-SAME:    (ptr noundef byval(%class.anon.1) align 4 %k, i32 noundef %a, i32 noundef %b) #[[NVPTX_ATTR0:[0-9]+]] {
+// CHECK-NVPTX-NEXT:  entry:
+// CHECK-NVPTX-NEXT:    %a.addr = alloca i32, align 4
+// CHECK-NVPTX-NEXT:    %b.addr = alloca i32, align 4
+// CHECK-NVPTX-NEXT:    store i32 %a, ptr %a.addr, align 4
+// CHECK-NVPTX-NEXT:    store i32 %b, ptr %b.addr, align 4
+// CHECK-NVPTX-NEXT:    %0 = load i32, ptr %a.addr, align 4
+// CHECK-NVPTX-NEXT:    %1 = load i32, ptr %b.addr, align 4
+// CHECK-NVPTX-NEXT:    %call = call noundef i32 @_ZZ4mainENKUliiE_clEii
+// CHECK-NVPTX-SAME:      (ptr noundef nonnull align 4 dereferenceable(4) %k, i32 noundef %0, i32 noundef %1) #[[NVPTX_ATTR1:[0-9]+]]
+// CHECK-NVPTX-NEXT:    ret void
+// CHECK-NVPTX-NEXT:  }
+//
+// CHECK-SPIRNV:      Function Attrs: convergent mustprogress noinline norecurse nounwind optnone
+// CHECK-SPIRNV-NEXT: define dso_local spir_kernel void @_ZTSZ4mainE2KN
+// CHECK-SPIRNV-SAME:   (ptr noundef %k, i32 noundef %a, i32 noundef %b) #[[SPIR_ATTR0:[0-9]+]] {
+// CHECK-SPIRNV-NEXT: entry:
+// CHECK-SPIRNV-NEXT:   %k.indirect_addr = alloca ptr addrspace(4), align {{[48]}}
+// CHECK-SPIRNV-NEXT:   %a.addr = alloca i32, align 4
+// CHECK-SPIRNV-NEXT:   %b.addr = alloca i32, align 4
+// CHECK-SPIRNV-NEXT:   %k.indirect_addr.ascast = addrspacecast ptr %k.indirect_addr to ptr addrspace(4)
+// CHECK-SPIRNV-NEXT:   %a.addr.ascast = addrspacecast ptr %a.addr to ptr addrspace(4)
+// CHECK-SPIRNV-NEXT:   %b.addr.ascast = addrspacecast ptr %b.addr to ptr addrspace(4)
+// CHECK-SPIRNV-NEXT:   store ptr %k, ptr addrspace(4) %k.indirect_addr.ascast, align {{[48]}}
+// CHECK-SPIRNV-NEXT:   %k.ascast = addrspacecast ptr %k to ptr addrspace(4)
+// CHECK-SPIRNV-NEXT:   store i32 %a, ptr addrspace(4) %a.addr.ascast, align 4
+// CHECK-SPIRNV-NEXT:   store i32 %b, ptr addrspace(4) %b.addr.ascast, align 4
+// CHECK-SPIRNV-NEXT:   %0 = load i32, ptr addrspace(4) %a.addr.ascast, align 4
+// CHECK-SPIRNV-NEXT:   %1 = load i32, ptr addrspace(4) %b.addr.ascast, align 4
+// CHECK-SPIRNV-NEXT:   %call = call spir_func noundef i32 @_ZZ4mainENKUliiE_clEii
+// CHECK-SPIRNV-SAME:     (ptr addrspace(4) noundef align 4 dereferenceable_or_null(4) %k.ascast, i32 noundef %0, i32 noundef %1) #[[SPIR_ATTR1:[0-9]+]]
+// CHECK-SPIRNV-NEXT:   ret void
+// CHECK-SPIRNV-NEXT: }
+//
+// CHECK-SPIRV:       Function Attrs: convergent mustprogress noinline norecurse nounwind optnone
+// CHECK-SPIRV-NEXT:  define spir_kernel void @_ZTSZ4mainE2KN
+// CHECK-SPIRV-SAME:    (ptr noundef byval(%class.anon.1) align 4 %k, i32 noundef %a, i32 noundef %b) #[[SPIR_ATTR0:[0-9]+]] {
+// CHECK-SPIRV-NEXT:  entry:
+// CHECK-SPIRV-NEXT:    %a.addr = alloca i32, align 4
+// CHECK-SPIRV-NEXT:    %b.addr = alloca i32, align 4
+// CHECK-SPIRV-NEXT:    %a.addr.ascast = addrspacecast ptr %a.addr to ptr addrspace(4)
+// CHECK-SPIRV-NEXT:    %b.addr.ascast = addrspacecast ptr %b.addr to ptr addrspace(4)
+// CHECK-SPIRV-NEXT:    %k.ascast = addrspacecast ptr %k to ptr addrspace(4)
+// CHECK-SPIRV-NEXT:    store i32 %a, ptr addrspace(4) %a.addr.ascast, align 4
+// CHECK-SPIRV-NEXT:    store i32 %b, ptr addrspace(4) %b.addr.ascast, align 4
+// CHECK-SPIRV-NEXT:    %0 = load i32, ptr addrspace(4) %a.addr.ascast, align 4
+// CHECK-SPIRV-NEXT:    %1 = load i32, ptr addrspace(4) %b.addr.ascast, align 4
+// CHECK-SPIRV-NEXT:    %call = call spir_func noundef i32 @_ZZ4mainENKUliiE_clEii
+// CHECK-SPIRV-SAME:      (ptr addrspace(4) noundef align 4 dereferenceable_or_null(4) %k.ascast, i32 noundef %0, i32 noundef %1) #[[SPIR_ATTR1:[0-9]+]]
+// CHECK-SPIRV-NEXT:    ret void
+// CHECK-SPIRV-NEXT:  }
 
 // CHECK-AMDGCN: #[[AMDGCN_ATTR0]] = { convergent mustprogress noinline norecurse nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" }
 // CHECK-AMDGCN: #[[AMDGCN_ATTR1]] = { convergent nounwind }
diff --git a/clang/test/CodeGenSYCL/unique_stable_name_windows_diff.cpp b/clang/test/CodeGenSYCL/unique_stable_name_windows_diff.cpp
index 63db83c02bbef..c298593e2f1ab 100644
--- a/clang/test/CodeGenSYCL/unique_stable_name_windows_diff.cpp
+++ b/clang/test/CodeGenSYCL/unique_stable_name_windows_diff.cpp
@@ -1,8 +1,8 @@
 // RUN: %clang_cc1 -triple spir64-unknown-unknown -aux-triple x86_64-pc-windows-msvc -fsycl-is-device -disable-llvm-passes -emit-llvm %s -o - | FileCheck %s '-D$ADDRSPACE=addrspace(1) '
 // RUN: %clang_cc1 -triple x86_64-pc-windows-msvc -fsycl-is-host -disable-llvm-passes -emit-llvm %s -o - | FileCheck %s '-D$ADDRSPACE='
 
-template <typename KernelName, typename KernelObj>
-void sycl_kernel_launch(const char *, KernelObj) {}
+template<typename KN, typename... Ts>
+void sycl_kernel_launch(const char *, Ts...) {}
 
 template<typename KN, typename Func>
 [[clang::sycl_kernel_entry_point(KN)]] void kernel(Func F){
diff --git a/clang/test/SemaSYCL/sycl-host-kernel-launch.cpp b/clang/test/SemaSYCL/sycl-host-kernel-launch.cpp
deleted file mode 100644
index eda0c4da489a9..0000000000000
--- a/clang/test/SemaSYCL/sycl-host-kernel-launch.cpp
+++ /dev/null
@@ -1,199 +0,0 @@
-// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++17 -fsyntax-only -fsycl-is-host -fcxx-exceptions -verify=host,expected %s
-// RUN: %clang_cc1 -triple x86_64-windows-msvc -std=c++17 -fsyntax-only -fsycl-is-host -fcxx-exceptions -verify=host,expected %s
-// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++17 -fsyntax-only -fsycl-is-device -fcxx-exceptions -verify=device,expected %s
-// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++20 -fsyntax-only -fsycl-is-host -fcxx-exceptions -verify=host,expected %s
-
-// A unique kernel name type is required for each declared kernel entry point.
-template<int, int = 0> struct KN;
-
-[[clang::sycl_kernel_entry_point(KN<1>)]]
-void nolauncher() {} 
-// host-error at -1 {{unable to find suitable 'sycl_kernel_launch' function for host code synthesis}}
-// device-warning at -2 {{unable to find suitable 'sycl_kernel_launch' function for host code synthesis}}
-// expected-note at -3 {{define 'sycl_kernel_launch' function template to fix}}
-
-void sycl_kernel_launch(const char *, int arg);
-// expected-note at -1 {{declared as a non-template here}}
-
-[[clang::sycl_kernel_entry_point(KN<2>)]]
-void nontemplatel() {}
-// host-error at -1 {{unable to find suitable 'sycl_kernel_launch' function for host code synthesis}}
-// device-warning at -2 {{unable to find suitable 'sycl_kernel_launch' function for host code synthesis}}
-// expected-note at -3 {{define 'sycl_kernel_launch' function template to fix}}
-// expected-error at -4 {{'sycl_kernel_launch' following the 'template' keyword does not refer to a template}}
-
-template <typename KernName>
-void sycl_kernel_launch(const char *, int arg);
-// expected-note at -1 {{candidate function template not viable: requires 2 arguments, but 1 was provided}}
-// expected-note at -2 2{{candidate function template not viable: no known conversion from 'Kern' to 'int' for 2nd argument}}
-
-[[clang::sycl_kernel_entry_point(KN<3>)]]
-void notenoughargs() {}
-// expected-error at -1 {{no matching function for call to 'sycl_kernel_launch'}}
-// FIXME: Should this also say "no suitable function for host code synthesis"?
-
-
-template <typename KernName>
-void sycl_kernel_launch(const char *, bool arg = 1);
-// expected-note at -1 2{{candidate function template not viable: no known conversion from 'Kern' to 'bool' for 2nd argument}}
-
-[[clang::sycl_kernel_entry_point(KN<4>)]]
-void enoughargs() {}
-
-namespace boop {
-template <typename KernName, typename KernelObj>
-void sycl_kernel_launch(const char *, KernelObj);
-
-template <typename KernName, typename KernelObj>
-[[clang::sycl_kernel_entry_point(KernName)]]
-void iboop(KernelObj Kernel) {
-  Kernel();
-}
-}
-
-template <typename KernName, typename KernelObj>
-[[clang::sycl_kernel_entry_point(KernName)]]
-void idontboop(KernelObj Kernel) {
-  Kernel();
-}
-// expected-error at -3 {{no matching function for call to 'sycl_kernel_launch'}}
-
-struct Kern {
-  int a;
-  int *b;
-  Kern(int _a, int* _b) : a(_a), b(_b) {}
-  void operator()(){ *b = a;}
-};
-
-void foo() {
-  int *a;
-  Kern b(1, a);
-  idontboop<KN<6>>(b);
-  // expected-note at -1 {{in instantiation of function template specialization 'idontboop<KN<6>, Kern>' requested here}}
-  boop::iboop<KN<7>>(b);
-}
-
-class MaybeHandler {
-
-template <typename KernName>
-void sycl_kernel_launch(const char *);
-
-template <typename KernName, typename... Tys>
-void sycl_kernel_launch(const char *, Tys ...Args);
-
-public:
-
-template <typename KernName, typename KernelObj>
-[[clang::sycl_kernel_entry_point(KernName)]]
-void entry(KernelObj Kernel) {
-  Kernel();
-}
-};
-
-class MaybeHandler2 {
-
-template <typename KernName, typename... Tys>
-static void sycl_kernel_launch(const char *, Tys ...Args);
-
-public:
-
-template <typename KernName, typename KernelObj>
-[[clang::sycl_kernel_entry_point(KernName)]]
-void entry(KernelObj Kernel) {
-  Kernel();
-}
-};
-
-class MaybeHandler3 {
-
-template <typename KernName, typename... Tys>
-static void sycl_kernel_launch(const char *, Tys ...Args);
-
-public:
-
-template <typename KernName, typename KernelObj>
-[[clang::sycl_kernel_entry_point(KernName)]]
-static void entry(KernelObj Kernel) {
-  Kernel();
-}
-};
-
-class MaybeHandler4 {
-
-template <typename KernName, typename... Tys>
-void sycl_kernel_launch(const char *, Tys ...Args);
-
-public:
-
-template <typename KernName, typename KernelObj>
-[[clang::sycl_kernel_entry_point(KernName)]]
-static void entry(KernelObj Kernel) { 
-  // expected-error at -1 {{call to non-static member function without an object argument}}
-  // FIXME: Should that be clearer?
-  Kernel();
-}
-};
-
-template<typename>
-struct base_handler {
-  template<typename KNT, typename... Ts>
-  void sycl_kernel_launch(const char*, Ts...) {}
-};
-struct derived_handler : base_handler<derived_handler> {
-  template<typename KNT, typename KT>
-  [[clang::sycl_kernel_entry_point(KNT)]]
-  void entry(KT k) { k(); }
-};
-
-template<int N>
-struct derived_handler_t : base_handler<derived_handler_t<N>> {
-  template<typename KNT, typename KT>
-// FIXME this fails because accessing members of dependent bases requires
-// explicit qualification.
-  [[clang::sycl_kernel_entry_point(KNT)]]
-  void entry(KT k) { k(); }
-  // expected-error at -1 {{no matching function for call to 'sycl_kernel_launch'}}
-};
-
-template<typename KNT>
-struct kernel_launcher {
-  template<typename... Ts>
-  void operator()(const char*, Ts...) const {}
-};
-
-namespace var {
-template<typename KNT>
-kernel_launcher<KNT> sycl_kernel_launch;
-
-struct handler {
-  template<typename KNT, typename KT>
-  [[clang::sycl_kernel_entry_point(KNT)]]
-  void entry(KT k) { k(); }
-};
-}
-
-
-void bar() {
-  int *a;
-  Kern b(1, a);
-  MaybeHandler H;
-  MaybeHandler2 H1;
-  MaybeHandler3 H2;
-  MaybeHandler4 H3;
-  H.entry<KN<8>>(b);
-  H1.entry<KN<9>>(b);
-  H2.entry<KN<10>>(b);
-  H3.entry<KN<11>>(b);
-
-  derived_handler H5;
-  H5.entry<KN<12>>(b);
-
-  derived_handler_t<13> H6;
-  H6.entry<KN<13>>(b); //expected-note {{in instantiation of function template specialization}}
-
-  var::handler h;
-  h.entry<KN<14>>(b);
-}
-
-
-
diff --git a/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-appertainment.cpp b/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-appertainment.cpp
index c181f76321a26..358ed18b6672b 100644
--- a/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-appertainment.cpp
+++ b/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-appertainment.cpp
@@ -40,10 +40,9 @@ struct coroutine_traits {
 // A unique kernel name type is required for each declared kernel entry point.
 template<int, int = 0> struct KN;
 
-// A launcher function definition required for host code synthesis to silence
-// complains.
-template <typename KernelName, typename... Tys>
-void sycl_kernel_launch(const char *, Tys &&...Args) {}
+// A generic kernel launch function.
+template<typename KNT, typename... Ts>
+void sycl_kernel_launch(const char *, Ts...) {}
 
 ////////////////////////////////////////////////////////////////////////////////
 // Valid declarations.
diff --git a/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-grammar.cpp b/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-grammar.cpp
index 1cdd48f1e5840..b1c9e270a02b8 100644
--- a/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-grammar.cpp
+++ b/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-grammar.cpp
@@ -10,10 +10,9 @@
 template<int> struct ST; // #ST-decl
 template<int N> using TTA = ST<N>; // #TTA-decl
 
-// A launcher function definition required for host code synthesis to silence
-// complains.
-template <typename KernelName, typename... Tys>
-void sycl_kernel_launch(const char *, Tys &&...Args) {}
+// A generic kernel launch function.
+template<typename KN, typename... Ts>
+void sycl_kernel_launch(const char *, Ts...) {}
 
 ////////////////////////////////////////////////////////////////////////////////
 // Valid declarations.
diff --git a/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-kernel-name-module.cpp b/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-kernel-name-module.cpp
index 44a3ce6f3640a..05a660e91e82c 100644
--- a/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-kernel-name-module.cpp
+++ b/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-kernel-name-module.cpp
@@ -17,10 +17,9 @@ module M2 { header "m2.h" }
 #--- common.h
 template<int> struct KN;
 
-// A launcher function definition required for host code synthesis to silence
-// complains.
-template <typename KernelName, typename... Tys>
-void sycl_kernel_launch(const char *, Tys &&...Args) {}
+// A generic kernel launch function.
+template<typename KN, typename... Ts>
+void sycl_kernel_launch(const char *, Ts...) {}
 
 [[clang::sycl_kernel_entry_point(KN<1>)]]
 void common_test1() {}
@@ -30,6 +29,7 @@ template<typename T>
 void common_test2() {}
 template void common_test2<KN<2>>();
 
+
 #--- m1.h
 #include "common.h"
 
diff --git a/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-kernel-name-pch.cpp b/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-kernel-name-pch.cpp
index 0e6d1a6c57e39..dcea60e016d12 100644
--- a/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-kernel-name-pch.cpp
+++ b/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-kernel-name-pch.cpp
@@ -15,10 +15,9 @@
 #--- pch.h
 template<int> struct KN;
 
-// A launcher function definition required for host code synthesis to silence
-// complains.
-template <typename KernelName, typename... Tys>
-void sycl_kernel_launch(const char *, Tys &&...Args) {}
+// A generic kernel launch function.
+template<typename KN, typename... Ts>
+void sycl_kernel_launch(const char *, Ts...) {}
 
 [[clang::sycl_kernel_entry_point(KN<1>)]]
 void pch_test1() {} // << expected previous declaration note here.
@@ -31,11 +30,11 @@ template void pch_test2<KN<2>>();
 
 #--- test.cpp
 // expected-error at +3 {{the 'clang::sycl_kernel_entry_point' kernel name argument conflicts with a previous declaration}}
-// expected-note at pch.h:9 {{previous declaration is here}}
+// expected-note at pch.h:8 {{previous declaration is here}}
 [[clang::sycl_kernel_entry_point(KN<1>)]]
 void test1() {}
 
 // expected-error at +3 {{the 'clang::sycl_kernel_entry_point' kernel name argument conflicts with a previous declaration}}
-// expected-note at pch.h:13 {{previous declaration is here}}
+// expected-note at pch.h:12 {{previous declaration is here}}
 [[clang::sycl_kernel_entry_point(KN<2>)]]
 void test2() {}
diff --git a/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-kernel-name.cpp b/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-kernel-name.cpp
index e2e6bf3314614..2abb24cde6663 100644
--- a/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-kernel-name.cpp
+++ b/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-kernel-name.cpp
@@ -10,10 +10,9 @@
 
 struct S1;
 
-// A launcher function definition required for host code synthesis to silence
-// complains.
-template <typename KernelName, typename... Tys>
-void sycl_kernel_launch(const char *, Tys &&...Args) {}
+// A generic kernel launch function.
+template<typename KernelName, typename... Ts>
+void sycl_kernel_launch(const char *, Ts...) {}
 
 // expected-warning at +3 {{redundant 'clang::sycl_kernel_entry_point' attribute}}
 // expected-note at +1  {{previous attribute is here}}
@@ -124,25 +123,3 @@ struct B19 {
 };
 // expected-note at +1 {{in instantiation of template class 'B19<int>' requested here}}
 B19<int> b19;
-
-struct auto_name;
-
-// expected-error at +4 {{the 'clang::sycl_kernel_entry_point' kernel name argument conflicts with a previous declaration}}
-// expected-note at +3 {{previous declaration is here}}
-template <typename KernelName, typename KernelType>
-[[clang::sycl_kernel_entry_point(KernelName)]]
-void __kernel_single_task(const KernelType KernelFunc) {
-  KernelFunc();
-}
-
-template <typename KernelType, typename KernelName = auto_name>
-void pf(KernelType K) {
-  // expected-note at +1 {{requested here}}
-  __kernel_single_task<KernelName>(K);
-}
-
-void foo() {
-  pf([](){});
-  // expected-note at +1 {{requested here}}
-  pf([](){});
-}
diff --git a/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-sfinae.cpp b/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-sfinae.cpp
index 9674dac456f9f..b39a77bd35878 100644
--- a/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-sfinae.cpp
+++ b/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-sfinae.cpp
@@ -10,10 +10,9 @@
 // attribute during instantiation of a specialization unless that specialization
 // is selected by overload resolution.
 
-// A launcher function definition required for host code synthesis to silence
-// complains.
-template <typename KernelName, typename... Tys>
-void sycl_kernel_launch(const char *, Tys &&...Args) {}
+// A generic kernel launch function.
+template<typename KernelName, typename... Ts>
+void sycl_kernel_launch(const char *, Ts...) {}
 
 // FIXME: C++23 [temp.expl.spec]p12 states:
 // FIXME:   ... Similarly, attributes appearing in the declaration of a template
diff --git a/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-this.cpp b/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-this.cpp
index 7b8fc6c9a7630..e4508710ee10b 100644
--- a/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-this.cpp
+++ b/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-this.cpp
@@ -22,10 +22,9 @@ struct type_info {
 };
 } // namespace std
 
-// A launcher function definition required for host code synthesis to silence
-// complains.
-template <typename KernelName, typename... Tys>
-void sycl_kernel_launch(const char *, Tys &&...Args) {}
+// A generic kernell launch function.
+template<typename KernelName, typename... Ts>
+void sycl_kernel_launch(const char *, Ts...) {}
 
 ////////////////////////////////////////////////////////////////////////////////
 // Valid declarations.
diff --git a/clang/test/SemaSYCL/sycl-kernel-launch.cpp b/clang/test/SemaSYCL/sycl-kernel-launch.cpp
new file mode 100644
index 0000000000000..74a82aa498aab
--- /dev/null
+++ b/clang/test/SemaSYCL/sycl-kernel-launch.cpp
@@ -0,0 +1,448 @@
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++17 -fsyntax-only -fsycl-is-host -fcxx-exceptions -verify=host,expected %s
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++17 -fsyntax-only -fsycl-is-device -verify=device,expected %s
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++20 -fsyntax-only -fsycl-is-host -fcxx-exceptions -verify=host,expected %s
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++20 -fsyntax-only -fsycl-is-device -verify=device,expected %s
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++23 -fsyntax-only -fsycl-is-host -fcxx-exceptions -verify=host,expected %s
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++23 -fsyntax-only -fsycl-is-device -verify=device,expected %s
+
+// Test overload resolution for implicit calls to sycl_kernel_launch<KN>(...)
+// synthesized for functions declared with the sycl_kernel_entry_point
+// attribute.
+
+////////////////////////////////////////////////////////////////////////////////
+// Valid declarations.
+////////////////////////////////////////////////////////////////////////////////
+
+// A unique kernel name type is required for each declared kernel entry point.
+template<int, int = 0> struct KN;
+
+// A generic kernel object type.
+template<int, int = 0>
+struct KT {
+  void operator()() const;
+};
+
+
+// sycl_kernel_launch as function template at namespace scope.
+namespace ok1 {
+  template<typename KN, typename... Ts>
+  void sycl_kernel_launch(const char *, Ts...);
+  [[clang::sycl_kernel_entry_point(KN<1>)]]
+  void skep(KT<1> k) {
+    k();
+  }
+}
+
+// sycl_kernel_launch as function template at namespace scope with default
+// template arguments and default function arguments..
+namespace ok2 {
+  template<typename KN, typename T = int>
+  void sycl_kernel_launch(const char *, KT<2>, T = 2);
+  [[clang::sycl_kernel_entry_point(KN<2>)]]
+  void skep(KT<2> k) {
+    k();
+  }
+}
+
+// sycl_kernel_launch as overload set.
+namespace ok3 {
+  template<typename KN>
+  void sycl_kernel_launch(const char *);
+  template<typename KN, typename... Ts>
+  void sycl_kernel_launch(const char *, Ts...);
+  [[clang::sycl_kernel_entry_point(KN<3>)]]
+  void skep(KT<3> k) {
+    k();
+  }
+}
+
+// sycl_kernel_launch as static member function template.
+namespace ok4 {
+  struct handler {
+  private:
+    template<typename KN, typename... Ts>
+    static void sycl_kernel_launch(const char *, Ts...);
+  public:
+    [[clang::sycl_kernel_entry_point(KN<4,0>)]]
+    static void skep(KT<4,0> k) {
+      k();
+    }
+    [[clang::sycl_kernel_entry_point(KN<4,1>)]]
+    void skep(KT<4,1> k) {
+      k();
+    }
+  };
+}
+
+// sycl_kernel_launch as non-static member function template.
+namespace ok5 {
+  struct handler {
+  private:
+    template<typename KN, typename... Ts>
+    void sycl_kernel_launch(const char *, Ts...);
+  public:
+    [[clang::sycl_kernel_entry_point(KN<5>)]]
+    void skep(KT<5> k) {
+      k();
+    }
+  };
+}
+
+#if __cplusplus >= 202302L
+// sycl_kernel_launch as non-static member function template with explicit
+// object parameter.
+namespace ok6 {
+  struct handler {
+  private:
+    template<typename KN, typename... Ts>
+    void sycl_kernel_launch(this handler self, const char *, Ts...);
+  public:
+    [[clang::sycl_kernel_entry_point(KN<6>)]]
+    void skep(KT<6> k) {
+      k();
+    }
+  };
+}
+#endif
+
+// sycl_kernel_launch as variable template.
+namespace ok7 {
+  template<typename KN>
+  struct launcher {
+    template<typename... Ts>
+    void operator()(const char *, Ts...);
+  };
+  template<typename KN>
+  launcher<KN> sycl_kernel_launch;
+  [[clang::sycl_kernel_entry_point(KN<7>)]]
+  void skep(KT<7> k) {
+    k();
+  }
+}
+
+#if __cplusplus >= 202302L
+// sycl_kernel_launch as variable template with static call operator template.
+namespace ok8 {
+  template<typename KN>
+  struct launcher {
+    template<typename... Ts>
+    static void operator()(const char *, Ts...);
+  };
+  template<typename KN>
+  launcher<KN> sycl_kernel_launch;
+  [[clang::sycl_kernel_entry_point(KN<8>)]]
+  void skep(KT<8> k) {
+    k();
+  }
+}
+#endif
+
+#if __cplusplus >= 202302L
+// sycl_kernel_launch as variable template with call operator template with
+// explicit object parameter.
+namespace ok9 {
+  template<typename KN>
+  struct launcher {
+    template<typename... Ts>
+    void operator()(this launcher self, const char *, Ts...);
+  };
+  template<typename KN>
+  launcher<KN> sycl_kernel_launch;
+  [[clang::sycl_kernel_entry_point(KN<9>)]]
+  void skep(KT<9> k) {
+    k();
+  }
+}
+#endif
+
+// sycl_kernel_launch as base class non-static member function template.
+namespace ok10 {
+  template<typename Derived>
+  struct base_handler {
+  protected:
+    template<typename KN, typename... Ts>
+    void sycl_kernel_launch(const char *, Ts...);
+  };
+  struct handler : protected base_handler<handler> {
+  public:
+    [[clang::sycl_kernel_entry_point(KN<10>)]]
+    void skep(KT<10> k) {
+      k();
+    }
+  };
+}
+
+// sycl_kernel_launch with forward reference parameters.
+namespace ok11 {
+  template<typename KN, typename... Ts>
+  void sycl_kernel_launch(const char *, Ts &&...);
+  struct non_copyable {
+    non_copyable(const non_copyable&) = delete;
+  };
+  struct non_moveable {
+    non_moveable(non_moveable&&) = delete;
+  };
+  [[clang::sycl_kernel_entry_point(KN<11>)]]
+  void skep(KT<11> k, non_copyable, non_moveable) {
+    k();
+  }
+}
+
+
+////////////////////////////////////////////////////////////////////////////////
+// Invalid declarations.
+////////////////////////////////////////////////////////////////////////////////
+
+// A unique kernel name type is required for each declared kernel entry point.
+template<int, int = 0> struct BADKN;
+
+// A generic kernel object type.
+template<int, int = 0>
+struct BADKT {
+  void operator()() const;
+};
+
+// Undeclared sycl_kernel_launch identifier.
+namespace bad1 {
+  // host-error at +5 {{unable to find suitable 'sycl_kernel_launch' function for host code synthesis}}
+  // device-warning at +4 {{unable to find suitable 'sycl_kernel_launch' function for host code synthesis}}
+  // expected-note at +3 {{define 'sycl_kernel_launch' function template to fix this problem}}
+  template<typename KN, typename KT>
+  [[clang::sycl_kernel_entry_point(KN)]]
+  void skep(KT k) {
+    k();
+  }
+  template void skep<BADKN<1>>(BADKT<1>);
+}
+
+// No matching function for call to sycl_kernel_launch; not a template.
+namespace bad2 {
+  // expected-note at +1 {{declared as a non-template here}}
+  void sycl_kernel_launch(const char *, BADKT<2>);
+  // expected-error at +5 {{'sycl_kernel_launch' does not refer to a template}}
+  // host-error at +4 {{unable to find suitable 'sycl_kernel_launch' function for host code synthesis}}
+  // device-warning at +3 {{unable to find suitable 'sycl_kernel_launch' function for host code synthesis}}
+  // expected-note at +2 {{define 'sycl_kernel_launch' function template to fix this problem}}
+  [[clang::sycl_kernel_entry_point(BADKN<2>)]]
+  void skep(BADKT<2> k) {
+    k();
+  }
+}
+
+// No matching function for call to sycl_kernel_launch; not enough arguments.
+namespace bad3 {
+  // expected-note at +2 {{candidate function template not viable: requires 2 arguments, but 1 was provided}}
+  template<typename KN, typename KT>
+  void sycl_kernel_launch(const char *, KT);
+  // expected-error at +3 {{no matching function for call to 'sycl_kernel_launch'}}
+  template<typename KN>
+  [[clang::sycl_kernel_entry_point(KN)]]
+  void skep() {}
+  // expected-note at +1 {{in instantiation of function template specialization 'bad3::skep<BADKN<3>>' requested here}}
+  template void skep<BADKN<3>>();
+}
+
+// No matching function for call to sycl_kernel_launch; too many arguments.
+namespace bad4 {
+  // expected-note at +2 {{candidate function template not viable: requires 2 arguments, but 3 were provided}}
+  template<typename KN, typename KT>
+  void sycl_kernel_launch(const char *, KT);
+  // expected-error at +3 {{no matching function for call to 'sycl_kernel_launch'}}
+  template<typename KN, typename KT>
+  [[clang::sycl_kernel_entry_point(KN)]]
+  void skep(KT k, int i) {
+    k();
+  }
+  // expected-note at +1 {{in instantiation of function template specialization 'bad4::skep<BADKN<4>, BADKT<4>>' requested here}}
+  template void skep<BADKN<4>>(BADKT<4>, int);
+}
+
+// No matching function for call to sycl_kernel_launch; mismatched function parameter type.
+namespace bad5 {
+  // expected-note at +2 {{candidate function template not viable: no known conversion from 'const char[21]' to 'int' for 1st argument}}
+  template<typename KN, typename... Ts>
+  void sycl_kernel_launch(int, Ts...);
+  // expected-error at +3 {{no matching function for call to 'sycl_kernel_launch'}}
+  template<typename KN, typename KT>
+  [[clang::sycl_kernel_entry_point(KN)]]
+  void skep(KT k) {
+    k();
+  }
+  // expected-note at +1 {{in instantiation of function template specialization 'bad5::skep<BADKN<5>, BADKT<5>>' requested here}}
+  template void skep<BADKN<5>>(BADKT<5>);
+}
+
+// No matching function for call to sycl_kernel_launch; mismatched template parameter kind.
+namespace bad6 {
+  // expected-note at +2 {{candidate template ignored: invalid explicitly-specified argument for 1st template parameter}}
+  template<int, typename... Ts>
+  void sycl_kernel_launch(const char *, Ts...);
+  // expected-error at +2 {{no matching function for call to 'sycl_kernel_launch'}}
+  [[clang::sycl_kernel_entry_point(BADKN<6>)]]
+  void skep(BADKT<6> k) {
+    k();
+  }
+}
+
+// No matching function for call to sycl_kernel_launch object; mismatched function parameter type.
+namespace bad7 {
+  template<typename KN>
+  struct launcher {
+    // expected-note at +2 {{candidate function template not viable: no known conversion from 'const char[21]' to 'int' for 1st argument}}
+    template<typename... Ts>
+    void operator()(int, Ts...);
+  };
+  template<typename KN>
+  launcher<KN> sycl_kernel_launch;
+  // expected-error at +3 {{no matching function for call to object of type 'launcher<BADKN<7, 0>>'}}
+  template<typename KN, typename KT>
+  [[clang::sycl_kernel_entry_point(KN)]]
+  void skep(KT k) {
+    k();
+  }
+  // expected-note at +1 {{in instantiation of function template specialization 'bad7::skep<BADKN<7>, BADKT<7>>' requested here}}
+  template void skep<BADKN<7>>(BADKT<7>);
+}
+
+// No matching function for call to sycl_kernel_launch object; mismatched template parameter kind.
+namespace bad8 {
+  template<int KN>
+  struct launcher {
+    template<typename... Ts>
+    void operator()(int, Ts...);
+  };
+  // expected-note at +1 {{template parameter is declared here}}
+  template<int KN>
+  launcher<KN> sycl_kernel_launch;
+  // expected-error at +3 {{template argument for non-type template parameter must be an expression}}
+  template<typename KN, typename KT>
+  [[clang::sycl_kernel_entry_point(KN)]]
+  void skep(KT k) {
+    k();
+  }
+  template void skep<BADKN<8>>(BADKT<8>);
+}
+
+// sycl_kernel_launch as variable template with private call operator template.
+namespace bad9 {
+  template<typename KN>
+  struct launcher {
+  private:
+    // expected-note at +2 {{declared private here}}
+    template<typename... Ts>
+    void operator()(const char *, Ts...);
+  };
+  template<typename KN>
+  launcher<KN> sycl_kernel_launch;
+  // expected-error at +2 {{'operator()' is a private member of 'bad9::launcher<BADKN<9>>'}}
+  [[clang::sycl_kernel_entry_point(BADKN<9>)]]
+  void skep(BADKT<9> k) {
+    k();
+  }
+}
+
+// Ambiguous reference to sycl_kernel_launch.
+namespace bad10 {
+  inline namespace in1 {
+    // expected-note at +2 {{candidate found by name lookup is 'bad10::in1::sycl_kernel_launch'}}
+    template<typename KN, typename... Ts>
+    void sycl_kernel_launch(const char *, Ts...);
+  }
+  inline namespace in2 {
+    template<typename KN>
+    struct launcher {
+      template<typename KT, typename... Ts>
+      void operator()(const char *, Ts...);
+    };
+    // expected-note at +2 {{candidate found by name lookup is 'bad10::in2::sycl_kernel_launch'}}
+    template<typename KN>
+    launcher<KN> sycl_kernel_launch;
+  }
+  // expected-error at +6 {{reference to 'sycl_kernel_launch' is ambiguous}}
+  // host-error at +5 {{unable to find suitable 'sycl_kernel_launch' function for host code synthesis}}
+  // device-warning at +4 {{unable to find suitable 'sycl_kernel_launch' function for host code synthesis}}
+  // expected-note at +3 {{define 'sycl_kernel_launch' function template to fix this problem}}
+  template<typename KN, typename KT>
+  [[clang::sycl_kernel_entry_point(KN)]]
+  void skep(KT k) {
+    k();
+  }
+  template void skep<BADKN<10>>(BADKT<10>);
+}
+
+// Ambiguous call to sycl_kernel_launch.
+namespace bad11 {
+  // expected-note at +2 {{candidate function [with KN = BADKN<11>, KT = BADKT<11>]}}
+  template<typename KN, typename KT>
+  void sycl_kernel_launch(const char *, KT, signed char);
+  // expected-note at +2 {{candidate function [with KN = BADKN<11>, KT = BADKT<11>]}}
+  template<typename KN, typename KT>
+  void sycl_kernel_launch(const char *, KT, unsigned char);
+  // expected-error at +2 {{call to 'sycl_kernel_launch' is ambiguous}}
+  [[clang::sycl_kernel_entry_point(BADKN<11>)]]
+  void skep(BADKT<11> k, int i) {
+    k();
+  }
+}
+
+// Call to member sycl_kernel_launch from non-static member.
+namespace bad12 {
+  struct S {
+    template<typename KN, typename... Ts>
+    void sycl_kernel_launch(const char *, Ts...);
+    // expected-error at +2 {{call to non-static member function without an object argument}}
+    [[clang::sycl_kernel_entry_point(BADKN<12>)]]
+    static void skep(BADKT<12> k) {
+      k();
+    }
+  };
+}
+
+// sycl_kernel_launch as dependent base class non-static member function
+// template.
+namespace bad13 {
+  template<typename Derived>
+  struct base_handler {
+  protected:
+    template<typename KN, typename... Ts>
+    void sycl_kernel_launch(const char *, Ts...);
+  };
+  template<int N>
+  struct handler : protected base_handler<handler<N>> {
+    // Lookup for sycl_kernel_launch fails because lookup in dependent base
+    // classes requires explicit qualification.
+    // host-error at +4 {{unable to find suitable 'sycl_kernel_launch' function for host code synthesis}}
+    // device-warning at +3 {{unable to find suitable 'sycl_kernel_launch' function for host code synthesis}}
+    // expected-note at +2 {{define 'sycl_kernel_launch' function template to fix this problem}}
+    [[clang::sycl_kernel_entry_point(BADKN<13>)]]
+    void skep(BADKT<13> k) {
+      k();
+    }
+  };
+  template void handler<13>::skep(BADKT<13>);
+}
+
+// sycl_kernel_launch with non-reference parameters and non-moveable arguments.
+namespace bad14 {
+  // expected-note at +2 2 {{passing argument to parameter here}}
+  template<typename KN, typename... Ts>
+  void sycl_kernel_launch(const char *, Ts...);
+  struct non_copyable {
+    // expected-note at +1 {{'non_copyable' has been explicitly marked deleted here}}
+    non_copyable(const non_copyable&) = delete;
+  };
+  // expected-error at +2 {{call to deleted constructor of 'bad14::non_copyable'}}
+  [[clang::sycl_kernel_entry_point(BADKN<14,0>)]]
+  void skep(BADKT<14,0> k, non_copyable) {
+    k();
+  }
+  struct non_moveable {
+    // expected-note at +1 {{copy constructor is implicitly deleted because 'non_moveable' has a user-declared move constructor}}
+    non_moveable(non_moveable&&) = delete;
+  };
+  // expected-error at +2 {{call to implicitly-deleted copy constructor of 'bad14::non_moveable'}}
+  [[clang::sycl_kernel_entry_point(BADKN<14,1>)]]
+  void skep(BADKT<14,1> k, non_moveable) {
+    k();
+  }
+}

>From a2b03230ef8269a8f37bb78006a1ecb365e4f854 Mon Sep 17 00:00:00 2001
From: Tom Honermann <tom.honermann at intel.com>
Date: Fri, 14 Nov 2025 14:29:58 -0800
Subject: [PATCH 10/29] Address clang-format complaints.

---
 clang/include/clang/AST/StmtSYCL.h | 4 ++--
 clang/lib/Sema/SemaDecl.cpp        | 4 ++--
 clang/lib/Sema/SemaSYCL.cpp        | 5 ++---
 clang/lib/Sema/TreeTransform.h     | 4 ++--
 4 files changed, 8 insertions(+), 9 deletions(-)

diff --git a/clang/include/clang/AST/StmtSYCL.h b/clang/include/clang/AST/StmtSYCL.h
index cce62466eec10..f3f4f040fb63c 100644
--- a/clang/include/clang/AST/StmtSYCL.h
+++ b/clang/include/clang/AST/StmtSYCL.h
@@ -125,8 +125,8 @@ class UnresolvedSYCLKernelCallStmt : public Stmt {
   void setKernelLaunchIdExpr(Expr *IdExpr) { KernelLaunchIdExpr = IdExpr; }
 
 public:
-  static UnresolvedSYCLKernelCallStmt *
-  Create(const ASTContext &C, CompoundStmt *CS, Expr *IdExpr) {
+  static UnresolvedSYCLKernelCallStmt *Create(const ASTContext &C,
+                                              CompoundStmt *CS, Expr *IdExpr) {
     return new (C) UnresolvedSYCLKernelCallStmt(CS, IdExpr);
   }
 
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 7badc3bc7abad..797b256bb3d7d 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -16351,8 +16351,8 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D,
 
   maybeAddDeclWithEffects(FD);
 
-  if (FD && !FD->isInvalidDecl() &&
-      FD->hasAttr<SYCLKernelEntryPointAttr>() && FnBodyScope) {
+  if (FD && !FD->isInvalidDecl() && FD->hasAttr<SYCLKernelEntryPointAttr>() &&
+      FnBodyScope) {
     // An implicit call expression is synthesized for functions declared with
     // the sycl_kernel_entry_point attribute. The call may resolve to a
     // function template, a member function template, or a call operator
diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp
index f0f39e99e8ae4..a21e0d845cb44 100644
--- a/clang/lib/Sema/SemaSYCL.cpp
+++ b/clang/lib/Sema/SemaSYCL.cpp
@@ -436,9 +436,8 @@ ExprResult SemaSYCL::BuildSYCLKernelLaunchIdExpr(FunctionDecl *FD,
                                               /*IsAddressOfOperand*/ false))
     // The lookup result allows for a possible implicit member access that
     // would require an implicit or explicit 'this' argument.
-    IdExpr = SemaRef.BuildPossibleImplicitMemberExpr(EmptySS, SourceLocation(),
-                                                     Result, &TALI,
-                                                     SemaRef.getCurScope());
+    IdExpr = SemaRef.BuildPossibleImplicitMemberExpr(
+        EmptySS, SourceLocation(), Result, &TALI, SemaRef.getCurScope());
   else
     IdExpr = SemaRef.BuildTemplateIdExpr(EmptySS, SourceLocation(), Result,
                                          /*RequiresADL*/ true, &TALI);
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 6b47e5af8e834..dd859e8c3b5fc 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -13065,11 +13065,11 @@ StmtResult TreeTransform<Derived>::TransformUnresolvedSYCLKernelCallStmt(
 
   ExprResult IdExpr = getDerived().TransformExpr(S->getKernelLaunchIdExpr());
   if (IdExpr.isInvalid())
-     return StmtError();
+    return StmtError();
 
   StmtResult Body = getDerived().TransformStmt(S->getOriginalStmt());
   if (Body.isInvalid())
-     return StmtError();
+    return StmtError();
 
   StmtResult SR = SemaRef.SYCL().BuildSYCLKernelCallStmt(
       cast<FunctionDecl>(SemaRef.CurContext), cast<CompoundStmt>(Body.get()),

>From 4bef45f5518cd77fb8027f2ea3d08be138788c6b Mon Sep 17 00:00:00 2001
From: Tom Honermann <tom.honermann at intel.com>
Date: Fri, 14 Nov 2025 18:11:34 -0800
Subject: [PATCH 11/29] Added support for passing arguments to
 sycl_kernel_launch as xvalues.

---
 clang/lib/Sema/SemaSYCL.cpp                   | 24 +++++++--
 .../ast-dump-sycl-kernel-call-stmt.cpp        | 50 +++++++++++--------
 clang/test/SemaSYCL/sycl-kernel-launch.cpp    | 26 ++++++++--
 3 files changed, 69 insertions(+), 31 deletions(-)

diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp
index a21e0d845cb44..736c2194ade36 100644
--- a/clang/lib/Sema/SemaSYCL.cpp
+++ b/clang/lib/Sema/SemaSYCL.cpp
@@ -456,8 +456,9 @@ namespace {
 
 // Constructs the arguments to be passed for the SYCL kernel launch call.
 // The first argument is a string literal that contains the SYCL kernel
-// name. The remaining arguments are the parameters of 'FD'.
-void BuildSYCLKernelLaunchCallArgs(Sema &SemaRef, FunctionDecl *FD,
+// name. The remaining arguments are the parameters of 'FD' passed as
+// move-elligible xvalues. Returns true on error and false otherwise.
+bool BuildSYCLKernelLaunchCallArgs(Sema &SemaRef, FunctionDecl *FD,
                                    const SYCLKernelInfo *SKI,
                                    SmallVectorImpl<Expr *> &Args,
                                    SourceLocation Loc) {
@@ -478,11 +479,23 @@ void BuildSYCLKernelLaunchCallArgs(Sema &SemaRef, FunctionDecl *FD,
                             /*Pascal*/ false, KernelNameArrayTy, Loc);
   Args.push_back(KernelNameExpr);
 
+  // Forward all parameters of 'FD' to the SYCL kernel launch function as if
+  // by std::move().
   for (ParmVarDecl *PVD : FD->parameters()) {
     QualType ParamType = PVD->getOriginalType().getNonReferenceType();
-    Expr *DRE = SemaRef.BuildDeclRefExpr(PVD, ParamType, VK_LValue, Loc);
-    Args.push_back(DRE);
+    ExprResult E = SemaRef.BuildDeclRefExpr(PVD, ParamType, VK_LValue, Loc);
+    if (E.isInvalid())
+      return true;
+    if (!PVD->getType()->isLValueReferenceType())
+      E = ImplicitCastExpr::Create(SemaRef.Context, E.get()->getType(), CK_NoOp,
+                                   E.get(), nullptr, VK_XValue,
+                                   FPOptionsOverride());
+    if (E.isInvalid())
+      return true;
+    Args.push_back(E.get());
   }
+
+  return false;
 }
 
 // Constructs the SYCL kernel launch call.
@@ -494,7 +507,8 @@ StmtResult BuildSYCLKernelLaunchCallStmt(Sema &SemaRef, FunctionDecl *FD,
   // IdExpr may be null if name lookup failed.
   if (IdExpr) {
     llvm::SmallVector<Expr *, 12> Args;
-    BuildSYCLKernelLaunchCallArgs(SemaRef, FD, SKI, Args, Loc);
+    if (BuildSYCLKernelLaunchCallArgs(SemaRef, FD, SKI, Args, Loc))
+      return StmtError();
     ExprResult LaunchResult =
         SemaRef.BuildCallExpr(SemaRef.getCurScope(), IdExpr, Loc, Args, Loc);
     if (LaunchResult.isInvalid())
diff --git a/clang/test/ASTSYCL/ast-dump-sycl-kernel-call-stmt.cpp b/clang/test/ASTSYCL/ast-dump-sycl-kernel-call-stmt.cpp
index 5eef5db069faf..c5518d9038448 100644
--- a/clang/test/ASTSYCL/ast-dump-sycl-kernel-call-stmt.cpp
+++ b/clang/test/ASTSYCL/ast-dump-sycl-kernel-call-stmt.cpp
@@ -92,8 +92,8 @@ void skep2<KN<2>>(K<2>);
 // CHECK-NEXT: |   | |   | `-DeclRefExpr {{.*}} 'void (const char *, K<2>)' lvalue Function {{.*}} 'sycl_kernel_launch' {{.*}}
 // CHECK-NEXT: |   | |   |-ImplicitCastExpr {{.*}} 'const char *' <ArrayToPointerDecay>
 // CHECK-NEXT: |   | |   | `-StringLiteral {{.*}} 'const char[14]' lvalue "_ZTS2KNILi2EE"
-// CHECK-NEXT: |   | |   `-CXXConstructExpr {{.*}} 'K<2>' 'void (const K<2> &) noexcept'
-// CHECK-NEXT: |   | |     `-ImplicitCastExpr {{.*}} <NoOp>
+// CHECK-NEXT: |   | |   `-CXXConstructExpr {{.*}} 'K<2>' 'void (K<2> &&) noexcept'
+// CHECK-NEXT: |   | |     `-ImplicitCastExpr {{.*}} 'K<2>' xvalue <NoOp>
 // CHECK-NEXT: |   | |       `-DeclRefExpr {{.*}} 'K<2>' lvalue ParmVar {{.*}} 'k' 'K<2>'
 // CHECK-NEXT: |   | `-OutlinedFunctionDecl {{.*}}
 // CHECK-NEXT: |   |   |-ImplicitParamDecl {{.*}} implicit used k 'K<2>'
@@ -148,8 +148,8 @@ void skep3<KN<3>>(K<3> k) {
 // CHECK-NEXT: | | |   | `-DeclRefExpr {{.*}} 'void (const char *, K<3>)' lvalue Function {{.*}} 'sycl_kernel_launch' 'void (const char *, K<3>)' {{.*}}
 // CHECK-NEXT: | | |   |-ImplicitCastExpr {{.*}} 'const char *' <ArrayToPointerDecay>
 // CHECK-NEXT: | | |   | `-StringLiteral {{.*}} 'const char[14]' lvalue "_ZTS2KNILi3EE"
-// CHECK-NEXT: | | |   `-CXXConstructExpr {{.*}} 'K<3>' 'void (const K<3> &) noexcept'
-// CHECK-NEXT: | | |     `-ImplicitCastExpr {{.*}} 'const K<3>' lvalue <NoOp>
+// CHECK-NEXT: | | |   `-CXXConstructExpr {{.*}} 'K<3>' 'void (K<3> &&) noexcept'
+// CHECK-NEXT: | | |     `-ImplicitCastExpr {{.*}} 'K<3>' xvalue <NoOp>
 // CHECK-NEXT: | | |       `-DeclRefExpr {{.*}} 'K<3>' lvalue ParmVar {{.*}} 'k' 'K<3>'
 // CHECK-NEXT: | | `-OutlinedFunctionDecl {{.*}}
 // CHECK-NEXT: | |   |-ImplicitParamDecl {{.*}} implicit used k 'K<3>'
@@ -186,13 +186,15 @@ void skep4(K<4> k, int p1, int p2) {
 // CHECK-NEXT: | | |   | `-DeclRefExpr {{.*}} 'void (const char *, K<4>, int, int)' lvalue Function {{.*}} 'sycl_kernel_launch' 'void (const char *, K<4>, int, int)' {{.*}}
 // CHECK-NEXT: | | |   |-ImplicitCastExpr {{.*}} 'const char *' <ArrayToPointerDecay>
 // CHECK-NEXT: | | |   | `-StringLiteral {{.*}} 'const char[14]' lvalue "_ZTS2KNILi4EE"
-// CHECK-NEXT: | | |   |-CXXConstructExpr {{.*}} 'K<4>' 'void (const K<4> &) noexcept'
-// CHECK-NEXT: | | |   | `-ImplicitCastExpr {{.*}} 'const K<4>' lvalue <NoOp>
+// CHECK-NEXT: | | |   |-CXXConstructExpr {{.*}} 'K<4>' 'void (K<4> &&) noexcept'
+// CHECK-NEXT: | | |   | `-ImplicitCastExpr {{.*}} 'K<4>' xvalue <NoOp>
 // CHECK-NEXT: | | |   |   `-DeclRefExpr {{.*}} 'K<4>' lvalue ParmVar {{.*}} 'k' 'K<4>'
 // CHECK-NEXT: | | |   |-ImplicitCastExpr {{.*}} 'int' <LValueToRValue>
-// CHECK-NEXT: | | |   | `-DeclRefExpr {{.*}} 'int' lvalue ParmVar {{.*}} 'p1' 'int'
+// CHECK-NEXT: | | |   | `-ImplicitCastExpr {{.*}} 'int' xvalue <NoOp>
+// CHECK-NEXT: | | |   |   `-DeclRefExpr {{.*}} 'int' lvalue ParmVar {{.*}} 'p1' 'int'
 // CHECK-NEXT: | | |   `-ImplicitCastExpr {{.*}} 'int' <LValueToRValue>
-// CHECK-NEXT: | | |     `-DeclRefExpr {{.*}} 'int' lvalue ParmVar {{.*}} 'p2' 'int'
+// CHECK-NEXT: | | |     `-ImplicitCastExpr {{.*}} 'int' xvalue <NoOp>
+// CHECK-NEXT: | | |       `-DeclRefExpr {{.*}} 'int' lvalue ParmVar {{.*}} 'p2' 'int'
 // CHECK-NEXT: | | `-OutlinedFunctionDecl {{.*}}
 // CHECK-NEXT: | |   |-ImplicitParamDecl {{.*}} implicit used k 'K<4>'
 // CHECK-NEXT: | |   |-ImplicitParamDecl {{.*}} implicit used p1 'int'
@@ -230,16 +232,20 @@ void skep5(int unused1, K<5> k, int unused2, int p, int unused3) {
 // CHECK-NEXT: | | |   |-ImplicitCastExpr {{.*}} 'const char *' <ArrayToPointerDecay>
 // CHECK-NEXT: | | |   | `-StringLiteral {{.*}} 'const char[14]' lvalue "_ZTS2KNILi5EE"
 // CHECK-NEXT: | | |   |-ImplicitCastExpr {{.*}} 'int' <LValueToRValue>
-// CHECK-NEXT: | | |   | `-DeclRefExpr {{.*}} 'int' lvalue ParmVar {{.*}} 'unused1' 'int'
-// CHECK-NEXT: | | |   |-CXXConstructExpr {{.*}} 'K<5>' 'void (const K<5> &) noexcept'
-// CHECK-NEXT: | | |   | `-ImplicitCastExpr {{.*}} 'const K<5>' lvalue <NoOp>
+// CHECK-NEXT: | | |   | `-ImplicitCastExpr {{.*}} 'int' xvalue <NoOp>
+// CHECK-NEXT: | | |   |   `-DeclRefExpr {{.*}} 'int' lvalue ParmVar {{.*}} 'unused1' 'int'
+// CHECK-NEXT: | | |   |-CXXConstructExpr {{.*}} 'K<5>' 'void (K<5> &&) noexcept'
+// CHECK-NEXT: | | |   | `-ImplicitCastExpr {{.*}} 'K<5>' xvalue <NoOp>
 // CHECK-NEXT: | | |   |   `-DeclRefExpr {{.*}} 'K<5>' lvalue ParmVar {{.*}} 'k' 'K<5>'
 // CHECK-NEXT: | | |   |-ImplicitCastExpr {{.*}} 'int' <LValueToRValue>
-// CHECK-NEXT: | | |   | `-DeclRefExpr {{.*}} 'int' lvalue ParmVar {{.*}} 'unused2' 'int'
+// CHECK-NEXT: | | |   | `-ImplicitCastExpr {{.*}} 'int' xvalue <NoOp>
+// CHECK-NEXT: | | |   |   `-DeclRefExpr {{.*}} 'int' lvalue ParmVar {{.*}} 'unused2' 'int'
 // CHECK-NEXT: | | |   |-ImplicitCastExpr {{.*}} 'int' <LValueToRValue>
-// CHECK-NEXT: | | |   | `-DeclRefExpr {{.*}} 'int' lvalue ParmVar {{.*}} 'p' 'int'
+// CHECK-NEXT: | | |   | `-ImplicitCastExpr {{.*}} 'int' xvalue <NoOp>
+// CHECK-NEXT: | | |   |   `-DeclRefExpr {{.*}} 'int' lvalue ParmVar {{.*}} 'p' 'int'
 // CHECK-NEXT: | | |   `-ImplicitCastExpr {{.*}} 'int' <LValueToRValue>
-// CHECK-NEXT: | | |     `-DeclRefExpr {{.*}} 'int' lvalue ParmVar {{.*}} 'unused3' 'int'
+// CHECK-NEXT: | | |     `-ImplicitCastExpr {{.*}} 'int' xvalue <NoOp>
+// CHECK-NEXT: | | |       `-DeclRefExpr {{.*}} 'int' lvalue ParmVar {{.*}} 'unused3' 'int'
 // CHECK-NEXT: | | `-OutlinedFunctionDecl {{.*}}
 // CHECK-NEXT: | |   |-ImplicitParamDecl {{.*}} implicit unused1 'int'
 // CHECK-NEXT: | |   |-ImplicitParamDecl {{.*}} implicit used k 'K<5>'
@@ -332,8 +338,8 @@ void skep7(S7 k) {
 // CHECK-NEXT: | | |   | `-DeclRefExpr {{.*}} 'void (const char *, S7)' lvalue Function {{.*}} 'sycl_kernel_launch' 'void (const char *, S7)' {{.*}}
 // CHECK-NEXT: | | |   |-ImplicitCastExpr {{.*}} 'const char *' <ArrayToPointerDecay>
 // CHECK-NEXT: | | |   | `-StringLiteral {{.*}} 'const char[14]' lvalue "_ZTS2KNILi7EE"
-// CHECK-NEXT: | | |   `-CXXConstructExpr {{.*}} 'S7' 'void (const S7 &) noexcept'
-// CHECK-NEXT: | | |     `-ImplicitCastExpr {{.*}} 'const S7' lvalue <NoOp>
+// CHECK-NEXT: | | |   `-CXXConstructExpr {{.*}} 'S7' 'void (S7 &&) noexcept'
+// CHECK-NEXT: | | |     `-ImplicitCastExpr {{.*}} 'S7' xvalue <NoOp>
 // CHECK-NEXT: | | |       `-DeclRefExpr {{.*}} 'S7' lvalue ParmVar {{.*}} 'k' 'S7'
 // CHECK-NEXT: | | `-OutlinedFunctionDecl {{.*}}
 // CHECK-NEXT: | |   |-ImplicitParamDecl {{.*}} implicit used k 'S7'
@@ -366,8 +372,8 @@ void skep8(S8 k) {
 // CHECK-NEXT: | | |   | `-DeclRefExpr {{.*}} 'void (const char *, S8)' lvalue Function {{.*}} 'sycl_kernel_launch' 'void (const char *, S8)' {{.*}}
 // CHECK-NEXT: | | |   |-ImplicitCastExpr {{.*}} 'const char *' <ArrayToPointerDecay>
 // CHECK-NEXT: | | |   | `-StringLiteral {{.*}} 'const char[12]' lvalue "_ZTS6\316\264\317\204\317\207"
-// CHECK-NEXT: | | |   `-CXXConstructExpr {{.*}} 'S8' 'void (const S8 &) noexcept'
-// CHECK-NEXT: | | |     `-ImplicitCastExpr {{.*}} 'const S8' lvalue <NoOp>
+// CHECK-NEXT: | | |   `-CXXConstructExpr {{.*}} 'S8' 'void (S8 &&) noexcept'
+// CHECK-NEXT: | | |     `-ImplicitCastExpr {{.*}} 'S8' xvalue <NoOp>
 // CHECK-NEXT: | | |       `-DeclRefExpr {{.*}} 'S8' lvalue ParmVar {{.*}} 'k' 'S8'
 // CHECK:      | | `-OutlinedFunctionDecl {{.*}}
 // CHECK:      | `-SYCLKernelEntryPointAttr {{.*}}
@@ -429,12 +435,14 @@ void foo() {
 // CHECK-NEXT: | |   | |   |-ImplicitCastExpr {{.*}} 'const char *' <ArrayToPointerDecay>
 // CHECK-NEXT: | |   | |   | `-StringLiteral {{.*}} 'const char[14]' lvalue "_ZTS2KNILi9EE"
 // CHECK-NEXT: | |   | |   |-CXXConstructExpr {{.*}}
-// CHECK-NEXT: | |   | |   | `-ImplicitCastExpr {{.*}} lvalue <NoOp>
+// CHECK-NEXT: | |   | |   | `-ImplicitCastExpr {{.*}} xvalue <NoOp>
 // CHECK-NEXT: | |   | |   |   `-DeclRefExpr {{.*}} lvalue ParmVar {{.*}} 'k' {{.*}}
 // CHECK-NEXT: | |   | |   |-ImplicitCastExpr {{.*}} 'int' <LValueToRValue>
-// CHECK-NEXT: | |   | |   | `-DeclRefExpr {{.*}} 'int' lvalue ParmVar {{.*}} 'a' 'int'
+// CHECK-NEXT: | |   | |   | `-ImplicitCastExpr {{.*}} 'int' xvalue <NoOp>
+// CHECK-NEXT: | |   | |   |   `-DeclRefExpr {{.*}} 'int' lvalue ParmVar {{.*}} 'a' 'int'
 // CHECK-NEXT: | |   | |   `-ImplicitCastExpr {{.*}} 'int' <LValueToRValue>
-// CHECK-NEXT: | |   | |     `-DeclRefExpr {{.*}} 'int' lvalue ParmVar {{.*}} 'b' 'int'
+// CHECK-NEXT: | |   | |     `-ImplicitCastExpr {{.*}} 'int' xvalue <NoOp>
+// CHECK-NEXT: | |   | |       `-DeclRefExpr {{.*}} 'int' lvalue ParmVar {{.*}} 'b' 'int'
 // CHECK-NEXT: | |   | `-OutlinedFunctionDecl {{.*}}
 // CHECK-NEXT: | |   |   |-ImplicitParamDecl {{.*}} implicit used k {{.*}}
 // CHECK-NEXT: | |   |   |-ImplicitParamDecl {{.*}} implicit used a 'int'
diff --git a/clang/test/SemaSYCL/sycl-kernel-launch.cpp b/clang/test/SemaSYCL/sycl-kernel-launch.cpp
index 74a82aa498aab..f69de9ab245bf 100644
--- a/clang/test/SemaSYCL/sycl-kernel-launch.cpp
+++ b/clang/test/SemaSYCL/sycl-kernel-launch.cpp
@@ -172,8 +172,21 @@ namespace ok10 {
   };
 }
 
-// sycl_kernel_launch with forward reference parameters.
+// sycl_kernel_launch with non-reference parameters.
 namespace ok11 {
+  template<typename KN, typename... Ts>
+  void sycl_kernel_launch(const char *, Ts...);
+  struct move_only {
+    move_only(move_only&&) = default;
+  };
+  [[clang::sycl_kernel_entry_point(KN<11>)]]
+  void skep(KT<11> k, move_only) {
+    k();
+  }
+}
+
+// sycl_kernel_launch with forward reference parameters.
+namespace ok12 {
   template<typename KN, typename... Ts>
   void sycl_kernel_launch(const char *, Ts &&...);
   struct non_copyable {
@@ -182,8 +195,11 @@ namespace ok11 {
   struct non_moveable {
     non_moveable(non_moveable&&) = delete;
   };
-  [[clang::sycl_kernel_entry_point(KN<11>)]]
-  void skep(KT<11> k, non_copyable, non_moveable) {
+  struct move_only {
+    move_only(move_only&&) = default;
+  };
+  [[clang::sycl_kernel_entry_point(KN<12>)]]
+  void skep(KT<12> k, non_copyable, non_moveable, move_only) {
     k();
   }
 }
@@ -437,10 +453,10 @@ namespace bad14 {
     k();
   }
   struct non_moveable {
-    // expected-note at +1 {{copy constructor is implicitly deleted because 'non_moveable' has a user-declared move constructor}}
+    // expected-note at +1 {{'non_moveable' has been explicitly marked deleted here}}
     non_moveable(non_moveable&&) = delete;
   };
-  // expected-error at +2 {{call to implicitly-deleted copy constructor of 'bad14::non_moveable'}}
+  // expected-error at +2 {{call to deleted constructor of 'bad14::non_moveable'}}
   [[clang::sycl_kernel_entry_point(BADKN<14,1>)]]
   void skep(BADKT<14,1> k, non_moveable) {
     k();

>From 34da054b3aa9c68ad483497673a92709a3650b04 Mon Sep 17 00:00:00 2001
From: Tom Honermann <tom.honermann at intel.com>
Date: Fri, 14 Nov 2025 19:36:43 -0800
Subject: [PATCH 12/29] Prohibited use of the sycl_kernel_entry_point attribute
 with a non-static member function with an explicit object parameter.

---
 clang/include/clang/Basic/AttrDocs.td         |  1 +
 .../clang/Basic/DiagnosticSemaKinds.td        |  3 ++-
 clang/lib/Sema/SemaSYCL.cpp                   |  7 +++++
 ...-kernel-entry-point-attr-appertainment.cpp | 26 ++++++++++++++++++
 .../sycl-kernel-entry-point-attr-this.cpp     | 27 ++++++++++---------
 5 files changed, 50 insertions(+), 14 deletions(-)

diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td
index 0ea8bc9e07d01..20097f1d28333 100644
--- a/clang/include/clang/Basic/AttrDocs.td
+++ b/clang/include/clang/Basic/AttrDocs.td
@@ -551,6 +551,7 @@ following requirements.
 
 * Has a non-deduced ``void`` return type.
 * Is not a constructor or destructor.
+* Is not a non-static member function with an explicit object parameter.
 * Is not a C variadic function.
 * Is not a coroutine.
 * Is not defined as deleted or as defaulted.
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 8771cffd0d03b..97f295bc6cd5d 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -13260,7 +13260,8 @@ def err_sycl_entry_point_invalid : Error<
       "%ConstexprFn{constexpr function}|"
       "%ConstevalFn{consteval function}|"
       "%NoreturnFn{function declared with the 'noreturn' attribute}|"
-      "%FunctionTryBlock{function defined with a function try block}"
+      "%FunctionTryBlock{function defined with a function try block}|"
+      "%ExplicitObjectFn{function with an explicit object parameter}|"
       "}1">;
 def err_sycl_entry_point_invalid_redeclaration : Error<
   "the %0 kernel name argument does not match prior"
diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp
index 736c2194ade36..c00a7dcaf82fa 100644
--- a/clang/lib/Sema/SemaSYCL.cpp
+++ b/clang/lib/Sema/SemaSYCL.cpp
@@ -325,6 +325,13 @@ void SemaSYCL::CheckSYCLEntryPointFunctionDecl(FunctionDecl *FD) {
         << SKEPAttr << diag::InvalidSKEPReason::Destructor;
     SKEPAttr->setInvalidAttr();
   }
+  if (const auto *MD = dyn_cast<CXXMethodDecl>(FD)) {
+    if (MD->isExplicitObjectMemberFunction()) {
+      Diag(SKEPAttr->getLocation(), diag::err_sycl_entry_point_invalid)
+          << SKEPAttr << diag::InvalidSKEPReason::ExplicitObjectFn;
+      SKEPAttr->setInvalidAttr();
+    }
+  }
 
   if (FD->isVariadic()) {
     Diag(SKEPAttr->getLocation(), diag::err_sycl_entry_point_invalid)
diff --git a/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-appertainment.cpp b/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-appertainment.cpp
index 358ed18b6672b..a17e4c1d1be0a 100644
--- a/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-appertainment.cpp
+++ b/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-appertainment.cpp
@@ -377,3 +377,29 @@ struct B42 {
   // expected-warning at +1 {{declaration does not declare anything}}
   [[clang::sycl_kernel_entry_point(BADKN<42>)]];
 };
+
+#if __cplusplus >= 202302L
+struct B43 {
+  // expected-error at +2 {{the 'clang::sycl_kernel_entry_point' attribute cannot be applied to a function with an explicit object parameter}}
+  template<typename KNT>
+  [[clang::sycl_kernel_entry_point(KNT)]]
+  void bad43(this B43) {}
+};
+#endif
+
+#if __cplusplus >= 202302L
+struct B44 {
+  // expected-error at +1 {{the 'clang::sycl_kernel_entry_point' attribute cannot be applied to a function with an explicit object parameter}}
+  [[clang::sycl_kernel_entry_point(BADKN<44>)]]
+  void bad44(this B44);
+};
+#endif
+
+#if __cplusplus >= 202302L
+template<typename KNT>
+struct B45 {
+  // expected-error at +1 {{the 'clang::sycl_kernel_entry_point' attribute cannot be applied to a function with an explicit object parameter}}
+  [[clang::sycl_kernel_entry_point(KNT)]]
+  void bad45(this B45);
+};
+#endif
diff --git a/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-this.cpp b/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-this.cpp
index e4508710ee10b..c9ab242754899 100644
--- a/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-this.cpp
+++ b/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-this.cpp
@@ -1,9 +1,9 @@
 // RUN: %clang_cc1 -triple x86_64-linux-gnu -fsyntax-only -std=c++17 -fsycl-is-host -verify %s
 // RUN: %clang_cc1 -triple x86_64-linux-gnu -fsyntax-only -std=c++17 -fsycl-is-device -verify %s
-// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsyntax-only -std=c++20 -fsycl-is-host -verify -DCXX20 %s
-// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsyntax-only -std=c++20 -fsycl-is-device -verify -DCXX20 %s
-// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsyntax-only -std=c++23 -fsycl-is-host -verify -DCXX23 %s
-// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsyntax-only -std=c++23 -fsycl-is-device -verify -DCXX23 %s
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsyntax-only -std=c++20 -fsycl-is-host -verify %s
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsyntax-only -std=c++20 -fsycl-is-device -verify %s
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsyntax-only -std=c++23 -fsycl-is-host -verify %s
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsyntax-only -std=c++23 -fsycl-is-device -verify %s
 
 // These tests validate diagnostics for invalid use of 'this' in the body of
 // a function declared with the sycl_kernel_entry_point attribute.
@@ -82,7 +82,7 @@ struct S7 {
 template void S7<KN<7,0>, false>::ok7();
 template void S7<KN<7,1>, true>::ok7();
 
-#if defined(CXX20)
+#if __cplusplus >= 202002L
 template<typename KN, typename T>
 struct S8 {
   void mf(T);
@@ -98,14 +98,6 @@ struct S9 {
 template void S9<KN<9>, int>::ok9();
 #endif
 
-#if defined(CXX23)
-struct S10 {
-  [[clang::sycl_kernel_entry_point(KN<10>)]] void ok10(this S10 self) {
-    (void)self;
-  }
-};
-#endif
-
 
 ////////////////////////////////////////////////////////////////////////////////
 // Invalid declarations.
@@ -185,3 +177,12 @@ struct B8 {
 };
 // expected-note at +1 {{in instantiation of member function 'B8<BADKN<8>>::bad8' requested here}}
 template void B8<BADKN<8>>::bad8();
+
+#if __cplusplus >= 202302L
+struct B9 {
+  // expected-error at +1 {{the 'clang::sycl_kernel_entry_point' attribute cannot be applied to a function with an explicit object parameter}}
+  [[clang::sycl_kernel_entry_point(BADKN<9>)]] void bad9(this B9 self) {
+    (void)self;
+  }
+};
+#endif

>From 90f1d04d41d2efe545f52a8c367903d1701055f5 Mon Sep 17 00:00:00 2001
From: Tom Honermann <tom.honermann at intel.com>
Date: Mon, 17 Nov 2025 20:39:42 -0800
Subject: [PATCH 13/29] Diagnostic improvements, additional tests.

Reworked diagnostics to include a synthesized code context and generation
of notes detailing implicit calls to sycl_kernel_launch().
---
 .../clang/Basic/DiagnosticSemaKinds.td        |  15 +-
 clang/include/clang/Sema/Sema.h               |  24 ++
 clang/lib/Frontend/FrontendActions.cpp        |   4 +
 clang/lib/Sema/SemaDecl.cpp                   |  33 ++-
 clang/lib/Sema/SemaSYCL.cpp                   |  53 +++-
 clang/lib/Sema/SemaTemplateInstantiate.cpp    |  47 +++-
 clang/lib/Sema/TreeTransform.h                |   2 +
 clang/test/CodeGenSYCL/function-attrs.cpp     |   3 +
 .../SemaSYCL/sycl-kernel-launch-ms-compat.cpp |  43 ++++
 clang/test/SemaSYCL/sycl-kernel-launch.cpp    | 235 ++++++++++++------
 10 files changed, 349 insertions(+), 110 deletions(-)
 create mode 100644 clang/test/SemaSYCL/sycl-kernel-launch-ms-compat.cpp

diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 97f295bc6cd5d..22b32631696e9 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -13284,15 +13284,12 @@ def err_sycl_entry_point_return_type : Error<
 def err_sycl_entry_point_deduced_return_type : Error<
   "the %0 attribute only applies to functions with a non-deduced 'void' return"
   " type">;
-def err_sycl_host_no_launch_function : Error<
-  "unable to find suitable 'sycl_kernel_launch' function for host code "
-  "synthesis">;
-def warn_sycl_device_no_host_launch_function : Warning<
-  "unable to find suitable 'sycl_kernel_launch' function for host code "
-  "synthesis">,
-  InGroup<DiagGroup<"sycl-host-launcher">>;
-def note_sycl_host_launch_function : Note<
-  "define 'sycl_kernel_launch' function template to fix this problem">;
+def note_sycl_kernel_launch_lookup_here : Note<
+  "in implicit call to 'sycl_kernel_launch' with template argument %0 required"
+  " here">;
+def note_sycl_kernel_launch_overload_resolution_here : Note<
+  "in implicit call to 'sycl_kernel_launch' with template argument %0 and"
+ " function arguments %1 required here">;
 
 def warn_cuda_maxclusterrank_sm_90 : Warning<
   "maxclusterrank requires sm_90 or higher, CUDA arch provided: %0, ignoring "
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 9ae2fa52a441a..9383e5c9c397e 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -13239,6 +13239,14 @@ class Sema final : public SemaBase {
 
       /// We are performing partial ordering for template template parameters.
       PartialOrderingTTP,
+
+      /// We are performing name lookup for a function template or variable
+      /// template named 'sycl_kernel_launch'.
+      SYCLKernelLaunchLookup,
+
+      /// We are performing overload resolution for a call to a function
+      /// template or variable template named 'sycl_kernel_launch'.
+      SYCLKernelLaunchOverloadResolution,
     } Kind;
 
     /// Whether we're substituting into constraints.
@@ -13594,6 +13602,22 @@ class Sema final : public SemaBase {
     operator=(const SynthesizedFunctionScope &) = delete;
   };
 
+  /// RAII object to ensure that a code synthesis context is popped on scope
+  /// exit.
+  class ScopedCodeSynthesisContext {
+    Sema &S;
+
+  public:
+    ScopedCodeSynthesisContext(Sema &S, const CodeSynthesisContext &Ctx)
+        : S(S) {
+      S.pushCodeSynthesisContext(Ctx);
+    }
+
+    ~ScopedCodeSynthesisContext() {
+      S.popCodeSynthesisContext();
+    }
+  };
+
   /// List of active code synthesis contexts.
   ///
   /// This vector is treated as a stack. As synthesis of one entity requires
diff --git a/clang/lib/Frontend/FrontendActions.cpp b/clang/lib/Frontend/FrontendActions.cpp
index f03b14058db40..492f7b1742bee 100644
--- a/clang/lib/Frontend/FrontendActions.cpp
+++ b/clang/lib/Frontend/FrontendActions.cpp
@@ -476,6 +476,10 @@ class DefaultTemplateInstCallback : public TemplateInstantiationCallback {
       return "TypeAliasTemplateInstantiation";
     case CodeSynthesisContext::PartialOrderingTTP:
       return "PartialOrderingTTP";
+    case CodeSynthesisContext::SYCLKernelLaunchLookup:
+      return "SYCLKernelLaunchLookup";
+    case CodeSynthesisContext::SYCLKernelLaunchOverloadResolution:
+      return "SYCLKernelLaunchOverloadResolution";
     }
     return "";
   }
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 797b256bb3d7d..5e31cc4a16e73 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -15931,6 +15931,7 @@ Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Declarator &D,
   if (!Bases.empty())
     OpenMP().ActOnFinishedFunctionDefinitionInOpenMPDeclareVariantScope(Dcl,
                                                                         Bases);
+
   return Dcl;
 }
 
@@ -16366,6 +16367,13 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D,
     if (!SKEPAttr->isInvalidAttr()) {
       ExprResult LaunchIdExpr =
           SYCL().BuildSYCLKernelLaunchIdExpr(FD, SKEPAttr->getKernelName());
+      if (LaunchIdExpr.isInvalid()) {
+        // Do not mark 'FD' as invalid. Name lookup failure for
+        // 'sycl_kernel_launch' is treated as an error in the definition of
+        // 'FD'; treating it as an error of the declaration would affect
+        // overload resolution.
+      }
+
       getCurFunction()->SYCLKernelLaunchIdExpr = LaunchIdExpr.get();
     }
   }
@@ -16578,20 +16586,31 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, bool IsInstantiation,
     // function or an explicit specialization.
     if (Body && !SKEPAttr->isInvalidAttr()) {
       StmtResult SR;
-      if (FD->isTemplated()) {
+      if (FD->isTemplateInstantiation()) {
+        // The function body should already be a SYCLKernelCallStmt in this
+        // case, but might not be if errors previous occurred.
+        SR = Body;
+      } else if (!getCurFunction()->SYCLKernelLaunchIdExpr) {
+        // If name lookup for a template named sycl_kernel_launch failed
+        // earlier, don't try to build a SYCL kernel call statement as that
+        // would cause additional errors to be issued; just proceed with the
+        // original function body.
+        SR = Body;
+      } else if (FD->isTemplated()) {
         SR = SYCL().BuildUnresolvedSYCLKernelCallStmt(
             cast<CompoundStmt>(Body), getCurFunction()->SYCLKernelLaunchIdExpr);
-      } else if (FD->isTemplateInstantiation()) {
-        assert(isa<SYCLKernelCallStmt>(Body));
-        SR = Body;
       } else {
         SR = SYCL().BuildSYCLKernelCallStmt(
             FD, cast<CompoundStmt>(Body),
             getCurFunction()->SYCLKernelLaunchIdExpr);
       }
-      if (SR.isInvalid())
-        return nullptr;
-      Body = SR.get();
+      // If construction of the replacement body fails, just continue with the
+      // original function body. An early error return here is not valid; the
+      // current declaration context and function scopes must be popped before
+      // returning.
+      if (SR.isUsable()) {
+        Body = SR.get();
+      }
     }
   }
 
diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp
index c00a7dcaf82fa..64efd6d7c07a2 100644
--- a/clang/lib/Sema/SemaSYCL.cpp
+++ b/clang/lib/Sema/SemaSYCL.cpp
@@ -414,30 +414,34 @@ ExprResult SemaSYCL::BuildSYCLKernelLaunchIdExpr(FunctionDecl *FD,
   IdentifierInfo &SYCLKernelLaunchID =
       Ctx.Idents.get("sycl_kernel_launch", tok::TokenKind::identifier);
 
+  // Establish a code synthesis context for the implicit name lookup of
+  // a template named 'sycl_kernel_launch'. In the event of an error, this
+  // ensures an appropriate diagnostic note is issued to explain why the
+  // lookup was performed.
+  Sema::CodeSynthesisContext CSC;
+  CSC.Kind = Sema::CodeSynthesisContext::SYCLKernelLaunchLookup;
+  CSC.Entity = FD;
+  Sema::ScopedCodeSynthesisContext ScopedCSC(SemaRef, CSC);
+
   // Perform ordinary name lookup for a function or variable template that
   // accepts a single type template argument.
   LookupResult Result(SemaRef, &SYCLKernelLaunchID, Loc,
                       Sema::LookupOrdinaryName);
   CXXScopeSpec EmptySS;
-  SemaRef.LookupTemplateName(Result, SemaRef.getCurScope(), EmptySS,
-                             /*ObjectType*/ QualType(),
-                             /*EnteringContext*/ false,
-                             Sema::TemplateNameIsRequired);
-
-  if (Result.empty() || Result.isAmbiguous()) {
-    SemaRef.Diag(Loc, SemaRef.getLangOpts().SYCLIsHost
-                          ? diag::err_sycl_host_no_launch_function
-                          : diag::warn_sycl_device_no_host_launch_function);
-    SemaRef.Diag(Loc, diag::note_sycl_host_launch_function);
-
+  if (SemaRef.LookupTemplateName(Result, SemaRef.getCurScope(), EmptySS,
+                                 /*ObjectType*/ QualType(),
+                                 /*EnteringContext*/ false,
+                                 Sema::TemplateNameIsRequired))
+    return ExprError();
+  if (Result.isAmbiguous())
     return ExprError();
-  }
 
   TemplateArgumentListInfo TALI{Loc, Loc};
   TemplateArgument KNTA = TemplateArgument(KNT);
   TemplateArgumentLoc TAL =
       SemaRef.getTrivialTemplateArgumentLoc(KNTA, QualType(), Loc);
   TALI.addArgument(TAL);
+
   ExprResult IdExpr;
   if (SemaRef.isPotentialImplicitMemberAccess(EmptySS, Result,
                                               /*IsAddressOfOperand*/ false))
@@ -510,18 +514,39 @@ StmtResult BuildSYCLKernelLaunchCallStmt(Sema &SemaRef, FunctionDecl *FD,
                                          const SYCLKernelInfo *SKI,
                                          Expr *IdExpr, SourceLocation Loc) {
   SmallVector<Stmt *> Stmts;
-
   // IdExpr may be null if name lookup failed.
   if (IdExpr) {
     llvm::SmallVector<Expr *, 12> Args;
+
+    // Establish a code synthesis context for construction of the arguments
+    // for the implicit call to 'sycl_kernel_launch'.
+    {
+    Sema::CodeSynthesisContext CSC;
+    CSC.Kind = Sema::CodeSynthesisContext::SYCLKernelLaunchLookup;
+    CSC.Entity = FD;
+    Sema::ScopedCodeSynthesisContext ScopedCSC(SemaRef, CSC);
+
     if (BuildSYCLKernelLaunchCallArgs(SemaRef, FD, SKI, Args, Loc))
       return StmtError();
+    }
+
+    // Establish a code synthesis context for the implicit call to
+    // 'sycl_kernel_launch'.
+    {
+    Sema::CodeSynthesisContext CSC;
+    CSC.Kind = Sema::CodeSynthesisContext::SYCLKernelLaunchOverloadResolution;
+    CSC.Entity = FD;
+    CSC.CallArgs = Args.data();
+    CSC.NumCallArgs = Args.size();
+    Sema::ScopedCodeSynthesisContext ScopedCSC(SemaRef, CSC);
+
     ExprResult LaunchResult =
         SemaRef.BuildCallExpr(SemaRef.getCurScope(), IdExpr, Loc, Args, Loc);
     if (LaunchResult.isInvalid())
       return StmtError();
 
     Stmts.push_back(SemaRef.MaybeCreateExprWithCleanups(LaunchResult).get());
+    }
   }
 
   return CompoundStmt::Create(SemaRef.getASTContext(), Stmts,
@@ -645,6 +670,8 @@ StmtResult SemaSYCL::BuildSYCLKernelCallStmt(FunctionDecl *FD,
   SourceLocation Loc = Body->getLBracLoc();
   StmtResult LaunchResult =
       BuildSYCLKernelLaunchCallStmt(SemaRef, FD, &SKI, LaunchIdExpr, Loc);
+  if (LaunchResult.isInvalid())
+    return StmtError();
 
   Stmt *NewBody =
       new (getASTContext()) SYCLKernelCallStmt(Body, LaunchResult.get(), OFD);
diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index 37309d057fbe7..3e70eb80fcd22 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -10,7 +10,6 @@
 //===----------------------------------------------------------------------===/
 
 #include "TreeTransform.h"
-#include "clang/AST/ASTConcept.h"
 #include "clang/AST/ASTConsumer.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/ASTLambda.h"
@@ -593,6 +592,8 @@ bool Sema::CodeSynthesisContext::isInstantiationRecord() const {
   case BuildingDeductionGuides:
   case TypeAliasTemplateInstantiation:
   case PartialOrderingTTP:
+  case SYCLKernelLaunchLookup:
+  case SYCLKernelLaunchOverloadResolution:
     return false;
 
   // This function should never be called when Kind's value is Memoization.
@@ -898,6 +899,25 @@ static std::string convertCallArgsToString(Sema &S,
   return Result;
 }
 
+static std::string
+printCallArgsValueCategoryAndType(Sema &S, llvm::ArrayRef<const Expr *> Args) {
+  std::string Result;
+  llvm::raw_string_ostream OS(Result);
+  llvm::ListSeparator Comma;
+  OS << "(";
+  for (const Expr *Arg : Args) {
+    ExprValueKind EVK = Arg->getValueKind();
+    const char *ValueCategory =
+        (EVK == VK_LValue ? "lvalue"
+                          : (EVK == VK_XValue ? "xvalue" : "prvalue"));
+    OS << Comma << ValueCategory << " of type '";
+    Arg->getType().print(OS, S.getPrintingPolicy());
+    OS << "'";
+  }
+  OS << ")";
+  return Result;
+}
+
 void Sema::PrintInstantiationStack(InstantiationContextDiagFuncRef DiagFunc) {
   // Determine which template instantiations to skip, if any.
   unsigned SkipStart = CodeSynthesisContexts.size(), SkipEnd = SkipStart;
@@ -1260,6 +1280,31 @@ void Sema::PrintInstantiationStack(InstantiationContextDiagFuncRef DiagFunc) {
                                << /*isTemplateTemplateParam=*/true
                                << Active->InstantiationRange);
       break;
+    case CodeSynthesisContext::SYCLKernelLaunchLookup: {
+      const auto *SKEPAttr =
+          Active->Entity->getAttr<SYCLKernelEntryPointAttr>();
+      assert(SKEPAttr && "Missing sycl_kernel_entry_point attribute");
+      assert(!SKEPAttr->isInvalidAttr() &&
+             "sycl_kernel_entry_point attribute is invalid");
+      DiagFunc(SKEPAttr->getLocation(),
+               PDiag(diag::note_sycl_kernel_launch_lookup_here)
+                   << SKEPAttr->getKernelName());
+      break;
+    }
+    case CodeSynthesisContext::SYCLKernelLaunchOverloadResolution: {
+      const auto *SKEPAttr =
+          Active->Entity->getAttr<SYCLKernelEntryPointAttr>();
+      assert(SKEPAttr && "Missing sycl_kernel_entry_point attribute");
+      assert(!SKEPAttr->isInvalidAttr() &&
+             "sycl_kernel_entry_point attribute is invalid");
+      DiagFunc(SKEPAttr->getLocation(),
+               PDiag(diag::note_sycl_kernel_launch_overload_resolution_here)
+                   << SKEPAttr->getKernelName()
+                   << printCallArgsValueCategoryAndType(
+                          *this, llvm::ArrayRef(Active->CallArgs,
+                                                Active->NumCallArgs)));
+      break;
+    }
     }
   }
 }
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index dd859e8c3b5fc..54b63a74b5810 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -13074,6 +13074,8 @@ StmtResult TreeTransform<Derived>::TransformUnresolvedSYCLKernelCallStmt(
   StmtResult SR = SemaRef.SYCL().BuildSYCLKernelCallStmt(
       cast<FunctionDecl>(SemaRef.CurContext), cast<CompoundStmt>(Body.get()),
       IdExpr.get());
+  if (SR.isInvalid())
+    return StmtError();
 
   return SR;
 }
diff --git a/clang/test/CodeGenSYCL/function-attrs.cpp b/clang/test/CodeGenSYCL/function-attrs.cpp
index 5f3de41aa6584..8640383dd363d 100644
--- a/clang/test/CodeGenSYCL/function-attrs.cpp
+++ b/clang/test/CodeGenSYCL/function-attrs.cpp
@@ -26,6 +26,9 @@ int foo() {
   return 1;
 }
 
+template <typename Name, typename... Ts>
+void sycl_kernel_launch(Ts...) {}
+
 template <typename Name, typename Func>
 [[clang::sycl_kernel_entry_point(Name)]] void kernel_single_task(const Func &kernelFunc) {
   kernelFunc();
diff --git a/clang/test/SemaSYCL/sycl-kernel-launch-ms-compat.cpp b/clang/test/SemaSYCL/sycl-kernel-launch-ms-compat.cpp
new file mode 100644
index 0000000000000..8125ec53fffed
--- /dev/null
+++ b/clang/test/SemaSYCL/sycl-kernel-launch-ms-compat.cpp
@@ -0,0 +1,43 @@
+// RUN: %clang_cc1 -triple x86_64-pc-windows-msvc -std=c++20 -fsyntax-only -fsycl-is-host -fms-compatibility -fcxx-exceptions -verify=host,expected %s
+// RUN: %clang_cc1 -triple x86_64-pc-windows-msvc -std=c++20 -fsyntax-only -fsycl-is-device -fms-compatibility -verify=device,expected %s
+
+// Test Microsoft extensions for lookup of a sycl_kernel_launch member template
+// in a dependent base class.
+
+////////////////////////////////////////////////////////////////////////////////
+// Valid declarations.
+////////////////////////////////////////////////////////////////////////////////
+
+// A unique kernel name type is required for each declared kernel entry point.
+template<int> struct KN;
+
+// A generic kernel object type.
+template<int>
+struct KT {
+  void operator()() const;
+};
+
+
+namespace ok1 {
+  template<typename Derived>
+  struct base_handler {
+  protected:
+    // expected-note at +2 {{must qualify identifier to find this declaration in dependent base class}}
+    template<typename KN, typename... Ts>
+    void sycl_kernel_launch(const char *, Ts...);
+  };
+  template<int N>
+  struct handler : protected base_handler<handler<N>> {
+    // A warning is issued because, in standard C++, unqualified lookup for
+    // sycl_kernel_launch would not consider dependent base classes. Such
+    // lookups are allowed as a Microsoft compatible extension.
+    // expected-warning at +3 {{use of member 'sycl_kernel_launch' found via unqualified lookup into dependent bases of class templates is a Microsoft extension}}
+    // expected-note-re at +1 {{in implicit call to 'sycl_kernel_launch' with template argument 'KN<1>' and function arguments (lvalue of type 'const char[{{[0-9]*}}]', xvalue of type 'KT<1>') required here}}
+    [[clang::sycl_kernel_entry_point(KN<1>)]]
+    void skep(KT<1> k) {
+      k();
+    }
+  };
+  // expected-note at +1 {{in instantiation of member function 'ok1::handler<1>::skep' requested here}}
+  template void handler<1>::skep(KT<1>);
+}
diff --git a/clang/test/SemaSYCL/sycl-kernel-launch.cpp b/clang/test/SemaSYCL/sycl-kernel-launch.cpp
index f69de9ab245bf..bf1d786e8be26 100644
--- a/clang/test/SemaSYCL/sycl-kernel-launch.cpp
+++ b/clang/test/SemaSYCL/sycl-kernel-launch.cpp
@@ -1,9 +1,9 @@
-// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++17 -fsyntax-only -fsycl-is-host -fcxx-exceptions -verify=host,expected %s
-// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++17 -fsyntax-only -fsycl-is-device -verify=device,expected %s
-// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++20 -fsyntax-only -fsycl-is-host -fcxx-exceptions -verify=host,expected %s
-// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++20 -fsyntax-only -fsycl-is-device -verify=device,expected %s
-// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++23 -fsyntax-only -fsycl-is-host -fcxx-exceptions -verify=host,expected %s
-// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++23 -fsyntax-only -fsycl-is-device -verify=device,expected %s
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++17 -fsyntax-only -fsycl-is-host -fcxx-exceptions -verify %s
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++17 -fsyntax-only -fsycl-is-device -verify %s
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++20 -fsyntax-only -fsycl-is-host -fcxx-exceptions -verify %s
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++20 -fsyntax-only -fsycl-is-device -verify %s
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++23 -fsyntax-only -fsycl-is-host -fcxx-exceptions -verify %s
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++23 -fsyntax-only -fsycl-is-device -verify %s
 
 // Test overload resolution for implicit calls to sycl_kernel_launch<KN>(...)
 // synthesized for functions declared with the sycl_kernel_entry_point
@@ -204,6 +204,21 @@ namespace ok12 {
   }
 }
 
+// ADL for sycl_kernel_launch.
+namespace ok13 {
+  template<typename KN, typename KT, typename T>
+  [[clang::sycl_kernel_entry_point(KN)]]
+  void skep(KT k, T t) {
+    k();
+  }
+  namespace nested {
+    template<typename KN, typename... Ts>
+    void sycl_kernel_launch(const char *, Ts...);
+    struct S13 {};
+  }
+  template void skep<KN<13>>(KT<13>, nested::S13);
+}
+
 
 ////////////////////////////////////////////////////////////////////////////////
 // Invalid declarations.
@@ -218,110 +233,149 @@ struct BADKT {
   void operator()() const;
 };
 
-// Undeclared sycl_kernel_launch identifier.
+// Undeclared sycl_kernel_launch identifier from non-template function.
 namespace bad1 {
-  // host-error at +5 {{unable to find suitable 'sycl_kernel_launch' function for host code synthesis}}
-  // device-warning at +4 {{unable to find suitable 'sycl_kernel_launch' function for host code synthesis}}
-  // expected-note at +3 {{define 'sycl_kernel_launch' function template to fix this problem}}
+  // expected-error at +3 {{use of undeclared identifier 'sycl_kernel_launch'}}
+  // expected-note-re at +1 {{in implicit call to 'sycl_kernel_launch' with template argument 'BADKN<1>' and function arguments (lvalue of type 'const char[{{[0-9]*}}]', xvalue of type 'BADKT<1>') required here}}
+  [[clang::sycl_kernel_entry_point(BADKN<1>)]]
+  void skep(BADKT<1> k) {
+    k();
+  }
+}
+
+// Undeclared sycl_kernel_launch identifier from function template.
+namespace bad2 {
+  // expected-error at +4 {{use of undeclared identifier 'sycl_kernel_launch'}}
+  // expected-note-re at +2 {{in implicit call to 'sycl_kernel_launch' with template argument 'BADKN<2>' and function arguments (lvalue of type 'const char[{{[0-9]*}}]', xvalue of type 'BADKT<2>') required here}}
   template<typename KN, typename KT>
   [[clang::sycl_kernel_entry_point(KN)]]
   void skep(KT k) {
     k();
   }
-  template void skep<BADKN<1>>(BADKT<1>);
+  // expected-note at +1 {{in instantiation of function template specialization 'bad2::skep<BADKN<2>, BADKT<2>>' requested here}}
+  template void skep<BADKN<2>>(BADKT<2>);
 }
 
 // No matching function for call to sycl_kernel_launch; not a template.
-namespace bad2 {
+namespace bad3 {
   // expected-note at +1 {{declared as a non-template here}}
-  void sycl_kernel_launch(const char *, BADKT<2>);
-  // expected-error at +5 {{'sycl_kernel_launch' does not refer to a template}}
-  // host-error at +4 {{unable to find suitable 'sycl_kernel_launch' function for host code synthesis}}
-  // device-warning at +3 {{unable to find suitable 'sycl_kernel_launch' function for host code synthesis}}
-  // expected-note at +2 {{define 'sycl_kernel_launch' function template to fix this problem}}
-  [[clang::sycl_kernel_entry_point(BADKN<2>)]]
-  void skep(BADKT<2> k) {
+  void sycl_kernel_launch(const char *, BADKT<3>);
+  // expected-error at +3 {{'sycl_kernel_launch' does not refer to a template}}
+  // expected-note at +1 {{in implicit call to 'sycl_kernel_launch' with template argument 'BADKN<3>' required here}}
+  [[clang::sycl_kernel_entry_point(BADKN<3>)]]
+  void skep(BADKT<3> k) {
     k();
   }
 }
 
 // No matching function for call to sycl_kernel_launch; not enough arguments.
-namespace bad3 {
+namespace bad4 {
   // expected-note at +2 {{candidate function template not viable: requires 2 arguments, but 1 was provided}}
   template<typename KN, typename KT>
   void sycl_kernel_launch(const char *, KT);
-  // expected-error at +3 {{no matching function for call to 'sycl_kernel_launch'}}
+  // expected-error at +4 {{no matching function for call to 'sycl_kernel_launch'}}
+  // expected-note-re at +2 {{in implicit call to 'sycl_kernel_launch' with template argument 'BADKN<4>' and function arguments (lvalue of type 'const char[{{[0-9]*}}]') required here}}
   template<typename KN>
   [[clang::sycl_kernel_entry_point(KN)]]
   void skep() {}
-  // expected-note at +1 {{in instantiation of function template specialization 'bad3::skep<BADKN<3>>' requested here}}
-  template void skep<BADKN<3>>();
+  // expected-note at +1 {{in instantiation of function template specialization 'bad4::skep<BADKN<4>>' requested here}}
+  template void skep<BADKN<4>>();
 }
 
 // No matching function for call to sycl_kernel_launch; too many arguments.
-namespace bad4 {
+namespace bad5 {
   // expected-note at +2 {{candidate function template not viable: requires 2 arguments, but 3 were provided}}
   template<typename KN, typename KT>
   void sycl_kernel_launch(const char *, KT);
-  // expected-error at +3 {{no matching function for call to 'sycl_kernel_launch'}}
+  // expected-error at +4 {{no matching function for call to 'sycl_kernel_launch'}}
+  // expected-note-re at +2 {{in implicit call to 'sycl_kernel_launch' with template argument 'BADKN<5>' and function arguments (lvalue of type 'const char[{{[0-9]*}}]', xvalue of type 'BADKT<5>', xvalue of type 'int') required here}}
   template<typename KN, typename KT>
   [[clang::sycl_kernel_entry_point(KN)]]
   void skep(KT k, int i) {
     k();
   }
-  // expected-note at +1 {{in instantiation of function template specialization 'bad4::skep<BADKN<4>, BADKT<4>>' requested here}}
-  template void skep<BADKN<4>>(BADKT<4>, int);
+  // expected-note at +1 {{in instantiation of function template specialization 'bad5::skep<BADKN<5>, BADKT<5>>' requested here}}
+  template void skep<BADKN<5>>(BADKT<5>, int);
 }
 
 // No matching function for call to sycl_kernel_launch; mismatched function parameter type.
-namespace bad5 {
-  // expected-note at +2 {{candidate function template not viable: no known conversion from 'const char[21]' to 'int' for 1st argument}}
+namespace bad6 {
+  // expected-note-re at +2 {{candidate function template not viable: no known conversion from 'const char[{{[0-9]*}}]' to 'int' for 1st argument}}
   template<typename KN, typename... Ts>
   void sycl_kernel_launch(int, Ts...);
-  // expected-error at +3 {{no matching function for call to 'sycl_kernel_launch'}}
+  // expected-error at +4 {{no matching function for call to 'sycl_kernel_launch'}}
+  // expected-note-re at +2 {{in implicit call to 'sycl_kernel_launch' with template argument 'BADKN<6>' and function arguments (lvalue of type 'const char[{{[0-9]*}}]', xvalue of type 'BADKT<6>') required here}}
   template<typename KN, typename KT>
   [[clang::sycl_kernel_entry_point(KN)]]
   void skep(KT k) {
     k();
   }
-  // expected-note at +1 {{in instantiation of function template specialization 'bad5::skep<BADKN<5>, BADKT<5>>' requested here}}
-  template void skep<BADKN<5>>(BADKT<5>);
+  // expected-note at +1 {{in instantiation of function template specialization 'bad6::skep<BADKN<6>, BADKT<6>>' requested here}}
+  template void skep<BADKN<6>>(BADKT<6>);
 }
 
 // No matching function for call to sycl_kernel_launch; mismatched template parameter kind.
-namespace bad6 {
+namespace bad7 {
   // expected-note at +2 {{candidate template ignored: invalid explicitly-specified argument for 1st template parameter}}
   template<int, typename... Ts>
   void sycl_kernel_launch(const char *, Ts...);
-  // expected-error at +2 {{no matching function for call to 'sycl_kernel_launch'}}
-  [[clang::sycl_kernel_entry_point(BADKN<6>)]]
-  void skep(BADKT<6> k) {
+  // expected-error at +3 {{no matching function for call to 'sycl_kernel_launch'}}
+  // expected-note-re at +1 {{in implicit call to 'sycl_kernel_launch' with template argument 'BADKN<7>' and function arguments (lvalue of type 'const char[{{[0-9]*}}]', xvalue of type 'BADKT<7>') required here}}
+  [[clang::sycl_kernel_entry_point(BADKN<7>)]]
+  void skep(BADKT<7> k) {
+    k();
+  }
+}
+
+// No matching function for call to sycl_kernel_launch; substitution failure.
+namespace bad8 {
+  // expected-note at +2 {{candidate template ignored: substitution failure [with KN = BADKN<8>, KT = BADKT<8>]: no type named 'no_such_type' in 'BADKT<8>'}}
+  template<typename KN, typename KT, typename T = typename KT::no_such_type>
+  void sycl_kernel_launch(const char *, KT);
+  // expected-error at +3 {{no matching function for call to 'sycl_kernel_launch'}}
+  // expected-note-re at +1 {{in implicit call to 'sycl_kernel_launch' with template argument 'BADKN<8>' and function arguments (lvalue of type 'const char[{{[0-9]*}}]', xvalue of type 'BADKT<8>') required here}}
+  [[clang::sycl_kernel_entry_point(BADKN<8>)]]
+  void skep(BADKT<8> k) {
+    k();
+  }
+}
+
+// No matching function for call to sycl_kernel_launch; deduction failure.
+namespace bad9 {
+  // expected-note at +2 {{candidate template ignored: couldn't infer template argument 'T'}}
+  template<typename KN, typename KT, typename T>
+  void sycl_kernel_launch(const char *, KT);
+  // expected-error at +3 {{no matching function for call to 'sycl_kernel_launch'}}
+  // expected-note-re at +1 {{in implicit call to 'sycl_kernel_launch' with template argument 'BADKN<9>' and function arguments (lvalue of type 'const char[{{[0-9]*}}]', xvalue of type 'BADKT<9>') required here}}
+  [[clang::sycl_kernel_entry_point(BADKN<9>)]]
+  void skep(BADKT<9> k) {
     k();
   }
 }
 
 // No matching function for call to sycl_kernel_launch object; mismatched function parameter type.
-namespace bad7 {
+namespace bad10 {
   template<typename KN>
   struct launcher {
-    // expected-note at +2 {{candidate function template not viable: no known conversion from 'const char[21]' to 'int' for 1st argument}}
+    // expected-note-re at +2 {{candidate function template not viable: no known conversion from 'const char[{{[0-9]*}}]' to 'int' for 1st argument}}
     template<typename... Ts>
     void operator()(int, Ts...);
   };
   template<typename KN>
   launcher<KN> sycl_kernel_launch;
-  // expected-error at +3 {{no matching function for call to object of type 'launcher<BADKN<7, 0>>'}}
+  // expected-error at +4 {{no matching function for call to object of type 'launcher<BADKN<10, 0>>'}}
+  // expected-note-re at +2 {{in implicit call to 'sycl_kernel_launch' with template argument 'BADKN<10>' and function arguments (lvalue of type 'const char[{{[0-9]*}}]', xvalue of type 'BADKT<10>') required here}}
   template<typename KN, typename KT>
   [[clang::sycl_kernel_entry_point(KN)]]
   void skep(KT k) {
     k();
   }
-  // expected-note at +1 {{in instantiation of function template specialization 'bad7::skep<BADKN<7>, BADKT<7>>' requested here}}
-  template void skep<BADKN<7>>(BADKT<7>);
+  // expected-note at +1 {{in instantiation of function template specialization 'bad10::skep<BADKN<10>, BADKT<10>>' requested here}}
+  template void skep<BADKN<10>>(BADKT<10>);
 }
 
 // No matching function for call to sycl_kernel_launch object; mismatched template parameter kind.
-namespace bad8 {
+namespace bad11 {
   template<int KN>
   struct launcher {
     template<typename... Ts>
@@ -330,17 +384,18 @@ namespace bad8 {
   // expected-note at +1 {{template parameter is declared here}}
   template<int KN>
   launcher<KN> sycl_kernel_launch;
-  // expected-error at +3 {{template argument for non-type template parameter must be an expression}}
+  // expected-error at +4 {{template argument for non-type template parameter must be an expression}}
+  // expected-note at +2 {{in implicit call to 'sycl_kernel_launch' with template argument 'KN' required here}}
   template<typename KN, typename KT>
   [[clang::sycl_kernel_entry_point(KN)]]
   void skep(KT k) {
     k();
   }
-  template void skep<BADKN<8>>(BADKT<8>);
+  template void skep<BADKN<11>>(BADKT<11>);
 }
 
 // sycl_kernel_launch as variable template with private call operator template.
-namespace bad9 {
+namespace bad12 {
   template<typename KN>
   struct launcher {
   private:
@@ -350,17 +405,18 @@ namespace bad9 {
   };
   template<typename KN>
   launcher<KN> sycl_kernel_launch;
-  // expected-error at +2 {{'operator()' is a private member of 'bad9::launcher<BADKN<9>>'}}
-  [[clang::sycl_kernel_entry_point(BADKN<9>)]]
-  void skep(BADKT<9> k) {
+  // expected-error at +3 {{'operator()' is a private member of 'bad12::launcher<BADKN<12>>'}}
+  // expected-note-re at +1 {{in implicit call to 'sycl_kernel_launch' with template argument 'BADKN<12>' and function arguments (lvalue of type 'const char[{{[0-9]*}}]', xvalue of type 'BADKT<12>') required here}}
+  [[clang::sycl_kernel_entry_point(BADKN<12>)]]
+  void skep(BADKT<12> k) {
     k();
   }
 }
 
 // Ambiguous reference to sycl_kernel_launch.
-namespace bad10 {
+namespace bad13 {
   inline namespace in1 {
-    // expected-note at +2 {{candidate found by name lookup is 'bad10::in1::sycl_kernel_launch'}}
+    // expected-note at +2 {{candidate found by name lookup is 'bad13::in1::sycl_kernel_launch'}}
     template<typename KN, typename... Ts>
     void sycl_kernel_launch(const char *, Ts...);
   }
@@ -370,45 +426,45 @@ namespace bad10 {
       template<typename KT, typename... Ts>
       void operator()(const char *, Ts...);
     };
-    // expected-note at +2 {{candidate found by name lookup is 'bad10::in2::sycl_kernel_launch'}}
+    // expected-note at +2 {{candidate found by name lookup is 'bad13::in2::sycl_kernel_launch'}}
     template<typename KN>
     launcher<KN> sycl_kernel_launch;
   }
-  // expected-error at +6 {{reference to 'sycl_kernel_launch' is ambiguous}}
-  // host-error at +5 {{unable to find suitable 'sycl_kernel_launch' function for host code synthesis}}
-  // device-warning at +4 {{unable to find suitable 'sycl_kernel_launch' function for host code synthesis}}
-  // expected-note at +3 {{define 'sycl_kernel_launch' function template to fix this problem}}
+  // expected-error at +4 {{reference to 'sycl_kernel_launch' is ambiguous}}
+  // expected-note at +2 {{in implicit call to 'sycl_kernel_launch' with template argument 'KN' required here}}
   template<typename KN, typename KT>
   [[clang::sycl_kernel_entry_point(KN)]]
   void skep(KT k) {
     k();
   }
-  template void skep<BADKN<10>>(BADKT<10>);
+  template void skep<BADKN<13>>(BADKT<13>);
 }
 
 // Ambiguous call to sycl_kernel_launch.
-namespace bad11 {
-  // expected-note at +2 {{candidate function [with KN = BADKN<11>, KT = BADKT<11>]}}
+namespace bad14 {
+  // expected-note at +2 {{candidate function [with KN = BADKN<14>, KT = BADKT<14>]}}
   template<typename KN, typename KT>
   void sycl_kernel_launch(const char *, KT, signed char);
-  // expected-note at +2 {{candidate function [with KN = BADKN<11>, KT = BADKT<11>]}}
+  // expected-note at +2 {{candidate function [with KN = BADKN<14>, KT = BADKT<14>]}}
   template<typename KN, typename KT>
   void sycl_kernel_launch(const char *, KT, unsigned char);
-  // expected-error at +2 {{call to 'sycl_kernel_launch' is ambiguous}}
-  [[clang::sycl_kernel_entry_point(BADKN<11>)]]
-  void skep(BADKT<11> k, int i) {
+  // expected-error at +3 {{call to 'sycl_kernel_launch' is ambiguous}}
+  // expected-note-re at +1 {{in implicit call to 'sycl_kernel_launch' with template argument 'BADKN<14>' and function arguments (lvalue of type 'const char[{{[0-9]*}}]', xvalue of type 'BADKT<14>', xvalue of type 'int') required here}}
+  [[clang::sycl_kernel_entry_point(BADKN<14>)]]
+  void skep(BADKT<14> k, int i) {
     k();
   }
 }
 
 // Call to member sycl_kernel_launch from non-static member.
-namespace bad12 {
+namespace bad15 {
   struct S {
     template<typename KN, typename... Ts>
     void sycl_kernel_launch(const char *, Ts...);
-    // expected-error at +2 {{call to non-static member function without an object argument}}
-    [[clang::sycl_kernel_entry_point(BADKN<12>)]]
-    static void skep(BADKT<12> k) {
+    // expected-error at +3 {{call to non-static member function without an object argument}}
+    // expected-note at +1 {{in implicit call to 'sycl_kernel_launch' with template argument 'BADKN<15>' required here}}
+    [[clang::sycl_kernel_entry_point(BADKN<15>)]]
+    static void skep(BADKT<15> k) {
       k();
     }
   };
@@ -416,10 +472,11 @@ namespace bad12 {
 
 // sycl_kernel_launch as dependent base class non-static member function
 // template.
-namespace bad13 {
+namespace bad16 {
   template<typename Derived>
   struct base_handler {
   protected:
+    // expected-note at +2 {{member is declared here}}
     template<typename KN, typename... Ts>
     void sycl_kernel_launch(const char *, Ts...);
   };
@@ -427,19 +484,19 @@ namespace bad13 {
   struct handler : protected base_handler<handler<N>> {
     // Lookup for sycl_kernel_launch fails because lookup in dependent base
     // classes requires explicit qualification.
-    // host-error at +4 {{unable to find suitable 'sycl_kernel_launch' function for host code synthesis}}
-    // device-warning at +3 {{unable to find suitable 'sycl_kernel_launch' function for host code synthesis}}
-    // expected-note at +2 {{define 'sycl_kernel_launch' function template to fix this problem}}
-    [[clang::sycl_kernel_entry_point(BADKN<13>)]]
-    void skep(BADKT<13> k) {
+    // expected-error at +3 {{explicit qualification required to use member 'sycl_kernel_launch' from dependent base class}}
+    // expected-note-re at +1 {{in implicit call to 'sycl_kernel_launch' with template argument 'BADKN<16>' and function arguments (lvalue of type 'const char[{{[0-9]*}}]', xvalue of type 'BADKT<16>') required here}}
+    [[clang::sycl_kernel_entry_point(BADKN<16>)]]
+    void skep(BADKT<16> k) {
       k();
     }
   };
-  template void handler<13>::skep(BADKT<13>);
+  // expected-note at +1 {{in instantiation of member function 'bad16::handler<16>::skep' requested here}}
+  template void handler<16>::skep(BADKT<16>);
 }
 
 // sycl_kernel_launch with non-reference parameters and non-moveable arguments.
-namespace bad14 {
+namespace bad17 {
   // expected-note at +2 2 {{passing argument to parameter here}}
   template<typename KN, typename... Ts>
   void sycl_kernel_launch(const char *, Ts...);
@@ -447,18 +504,36 @@ namespace bad14 {
     // expected-note at +1 {{'non_copyable' has been explicitly marked deleted here}}
     non_copyable(const non_copyable&) = delete;
   };
-  // expected-error at +2 {{call to deleted constructor of 'bad14::non_copyable'}}
-  [[clang::sycl_kernel_entry_point(BADKN<14,0>)]]
-  void skep(BADKT<14,0> k, non_copyable) {
+  // expected-error at +3 {{call to deleted constructor of 'bad17::non_copyable'}}
+  // expected-note-re at +1 {{in implicit call to 'sycl_kernel_launch' with template argument 'BADKN<17, 0>' and function arguments (lvalue of type 'const char[{{[0-9]*}}]', xvalue of type 'BADKT<17, 0>', xvalue of type 'non_copyable') required here}}
+  [[clang::sycl_kernel_entry_point(BADKN<17,0>)]]
+  void skep(BADKT<17,0> k, non_copyable) {
     k();
   }
   struct non_moveable {
     // expected-note at +1 {{'non_moveable' has been explicitly marked deleted here}}
     non_moveable(non_moveable&&) = delete;
   };
-  // expected-error at +2 {{call to deleted constructor of 'bad14::non_moveable'}}
-  [[clang::sycl_kernel_entry_point(BADKN<14,1>)]]
-  void skep(BADKT<14,1> k, non_moveable) {
+  // expected-error at +3 {{call to deleted constructor of 'bad17::non_moveable'}}
+  // expected-note-re at +1 {{in implicit call to 'sycl_kernel_launch' with template argument 'BADKN<17, 1>' and function arguments (lvalue of type 'const char[{{[0-9]*}}]', xvalue of type 'BADKT<17, 1>', xvalue of type 'non_moveable') required here}}
+  [[clang::sycl_kernel_entry_point(BADKN<17,1>)]]
+  void skep(BADKT<17,1> k, non_moveable) {
     k();
   }
 }
+
+// sycl_kernel_launch declared after use and not found by ADL.
+namespace bad18 {
+  // expected-error at +4 {{call to function 'sycl_kernel_launch' that is neither visible in the template definition nor found by argument-dependent lookup}}
+  // expected-note-re at +2 {{in implicit call to 'sycl_kernel_launch' with template argument 'BADKN<18>' and function arguments (lvalue of type 'const char[{{[0-9]*}}]', xvalue of type 'BADKT<18>') required here}}
+  template<typename KN, typename KT>
+  [[clang::sycl_kernel_entry_point(KN)]]
+  void skep(KT k) {
+    k();
+  }
+  // expected-note at +2 {{'sycl_kernel_launch' should be declared prior to the call site or in the global namespace}}
+  template<typename KN, typename... Ts>
+  void sycl_kernel_launch(Ts...) {}
+  // expected-note at +1 {{in instantiation of function template specialization 'bad18::skep<BADKN<18>, BADKT<18>>' requested here}}
+  template void skep<BADKN<18>>(BADKT<18>);
+}

>From 13b20897d2cbccc856e447208f5f0dce61fd3741 Mon Sep 17 00:00:00 2001
From: Tom Honermann <tom.honermann at intel.com>
Date: Mon, 17 Nov 2025 20:57:43 -0800
Subject: [PATCH 14/29] Make clang-format happy again.

---
 clang/include/clang/Sema/Sema.h |  4 +---
 clang/lib/Sema/SemaSYCL.cpp     | 38 ++++++++++++++++-----------------
 2 files changed, 20 insertions(+), 22 deletions(-)

diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 9383e5c9c397e..f30b8d15487a3 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -13613,9 +13613,7 @@ class Sema final : public SemaBase {
       S.pushCodeSynthesisContext(Ctx);
     }
 
-    ~ScopedCodeSynthesisContext() {
-      S.popCodeSynthesisContext();
-    }
+    ~ScopedCodeSynthesisContext() { S.popCodeSynthesisContext(); }
   };
 
   /// List of active code synthesis contexts.
diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp
index 64efd6d7c07a2..f5c2418076e6e 100644
--- a/clang/lib/Sema/SemaSYCL.cpp
+++ b/clang/lib/Sema/SemaSYCL.cpp
@@ -521,31 +521,31 @@ StmtResult BuildSYCLKernelLaunchCallStmt(Sema &SemaRef, FunctionDecl *FD,
     // Establish a code synthesis context for construction of the arguments
     // for the implicit call to 'sycl_kernel_launch'.
     {
-    Sema::CodeSynthesisContext CSC;
-    CSC.Kind = Sema::CodeSynthesisContext::SYCLKernelLaunchLookup;
-    CSC.Entity = FD;
-    Sema::ScopedCodeSynthesisContext ScopedCSC(SemaRef, CSC);
+      Sema::CodeSynthesisContext CSC;
+      CSC.Kind = Sema::CodeSynthesisContext::SYCLKernelLaunchLookup;
+      CSC.Entity = FD;
+      Sema::ScopedCodeSynthesisContext ScopedCSC(SemaRef, CSC);
 
-    if (BuildSYCLKernelLaunchCallArgs(SemaRef, FD, SKI, Args, Loc))
-      return StmtError();
+      if (BuildSYCLKernelLaunchCallArgs(SemaRef, FD, SKI, Args, Loc))
+        return StmtError();
     }
 
     // Establish a code synthesis context for the implicit call to
     // 'sycl_kernel_launch'.
     {
-    Sema::CodeSynthesisContext CSC;
-    CSC.Kind = Sema::CodeSynthesisContext::SYCLKernelLaunchOverloadResolution;
-    CSC.Entity = FD;
-    CSC.CallArgs = Args.data();
-    CSC.NumCallArgs = Args.size();
-    Sema::ScopedCodeSynthesisContext ScopedCSC(SemaRef, CSC);
-
-    ExprResult LaunchResult =
-        SemaRef.BuildCallExpr(SemaRef.getCurScope(), IdExpr, Loc, Args, Loc);
-    if (LaunchResult.isInvalid())
-      return StmtError();
-
-    Stmts.push_back(SemaRef.MaybeCreateExprWithCleanups(LaunchResult).get());
+      Sema::CodeSynthesisContext CSC;
+      CSC.Kind = Sema::CodeSynthesisContext::SYCLKernelLaunchOverloadResolution;
+      CSC.Entity = FD;
+      CSC.CallArgs = Args.data();
+      CSC.NumCallArgs = Args.size();
+      Sema::ScopedCodeSynthesisContext ScopedCSC(SemaRef, CSC);
+
+      ExprResult LaunchResult =
+          SemaRef.BuildCallExpr(SemaRef.getCurScope(), IdExpr, Loc, Args, Loc);
+      if (LaunchResult.isInvalid())
+        return StmtError();
+
+      Stmts.push_back(SemaRef.MaybeCreateExprWithCleanups(LaunchResult).get());
     }
   }
 

>From 443103ba194f6b98e6b33f32f147c28ae4fc67c4 Mon Sep 17 00:00:00 2001
From: Tom Honermann <tom.honermann at intel.com>
Date: Thu, 20 Nov 2025 21:51:43 -0800
Subject: [PATCH 15/29] Reworded much of the sycl_kernel_entry_point attribute
 documentation.

Prompted by code review, this rewording is intended to clarify the
prose and better tie it to the example code. Mention of kernel
argument decomposition and reconstruction is removed since such support
is not yet implemented. Additional changes include use of identifiers
that match the SYCL specification for consistency, avoidance of
duplication, a change of std::forward<>() to std::move(), and oher
misc edits.
---
 clang/include/clang/Basic/AttrDocs.td | 190 ++++++++++++--------------
 1 file changed, 87 insertions(+), 103 deletions(-)

diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td
index 20097f1d28333..4885d21ddd57f 100644
--- a/clang/include/clang/Basic/AttrDocs.td
+++ b/clang/include/clang/Basic/AttrDocs.td
@@ -540,11 +540,11 @@ SYCL kernel invocation functions like the ``single_task`` and ``parallel_for``
 member functions of the ``sycl::handler`` class specified in section 4.9.4,
 "Command group ``handler`` class", of the SYCL 2020 specification.
 
-The attribute requires a single type argument that specifies a class type that
-meets the requirements for a SYCL kernel name as described in section 5.2,
-"Naming of kernels", of the SYCL 2020 specification. A unique kernel name type
-is required for each function declared with the attribute. The attribute may
-not first appear on a declaration that follows a definition of the function.
+The attribute requires a single type argument that meets the requirements for
+a SYCL kernel name as described in section 5.2, "Naming of kernels", of the
+SYCL 2020 specification. A unique kernel name type is required for each
+function declared with the attribute. The attribute may not first appear on a
+declaration that follows a definition of the function.
 
 The attribute only appertains to functions and only those that meet the
 following requirements.
@@ -566,34 +566,42 @@ follows.
 
   namespace sycl {
   class handler {
-    template<typename KernelNameType, typename... Ts>
-    void sycl_kernel_launch(const char *KernelName, Ts...) {
-      // Call functions appropriate for the desired offload backend
-      // (OpenCL, CUDA, HIP, Level Zero, etc...) to enqueue kernel invocation.
+    template<typename KernelName, typename... Ts>
+    void sycl_kernel_launch(const char* kernelSymbol, Ts&&... kernelArgs) {
+      // This code will run on the host and is responsible for calling functions
+      // appropriate for the desired offload backend (OpenCL, CUDA, HIP,
+      // Level Zero, etc...) to copy the kernel arguments denoted by kernelArgs
+      // to a device and to schedule an invocation of the offload kernel entry
+      // point denoted by kernelSymbol with the copied arguments.
     }
 
-    template<typename KernelNameType, typename KernelType>
-    [[ clang::sycl_kernel_entry_point(KernelNameType) ]]
-    void kernel_entry_point(KernelType Kernel) {
-      Kernel();
+    template<typename KernelName, typename KernelType>
+    [[ clang::sycl_kernel_entry_point(KernelName) ]]
+    void kernel_entry_point(KernelType kernelFunc) {
+      // This code will run on the device. The call to kernelFunc() invokes
+      // the SYCL kernel.
+      kernelFunc();
     }
 
   public:
-    template<typename KernelNameType, typename KernelType>
-    void single_task(KernelType Kernel) {
-      // Call kernel_entry_point() to launch the kernel and to trigger
-      // generation of an offload kernel entry point.
-      kernel_entry_point<KernelNameType>(Kernel);
+    template<typename KernelName, typename KernelType>
+    void single_task(const KernelType& kernelFunc) {
+      // This code will run on the host. kernel_entry_point() is called to
+      // trigger generation of an offload kernel entry point and to schedule
+      // an invocation of it on a device with kernelFunc (a SYCL kernel object)
+      // passed as a kernel argument. This call will result in an implicit call
+      // to sycl_kernel_launch() with the symbol name for the generated offload
+      // kernel entry point passed as the first function argument followed by
+      // kernelFunc.
+      kernel_entry_point<KernelName>(kernelFunc);
     }
   };
   } // namespace sycl
 
 A SYCL kernel object is a callable object of class type that is constructed on
 a host, often via a lambda expression, and then passed to a SYCL kernel
-invocation function to be executed on an offload device. A SYCL kernel
-invocation function is responsible for copying the provided SYCL kernel object
-to an offload device and initiating a call to it. The SYCL kernel object and
-its data members constitute the parameters of an offload kernel.
+invocation function to be executed on an offload device. The ``kernelFunc``
+parameters in the example code above correspond to SYCL kernel objects.
 
 A SYCL kernel object type is required to satisfy the device copyability
 requirements specified in section 3.13.1, "Device copyable", of the SYCL 2020
@@ -601,46 +609,39 @@ specification. Additionally, any data members of the kernel object type are
 required to satisfy section 4.12.4, "Rules for parameter passing to kernels".
 For most types, these rules require that the type is trivially copyable.
 However, the SYCL specification mandates that certain special SYCL types, such
-as ``sycl::accessor`` and ``sycl::stream`` be device copyable even if they are
+as ``sycl::accessor`` and ``sycl::stream``, be device copyable even if they are
 not trivially copyable. These types require special handling because they cannot
-be copied to device memory as if by ``memcpy()``. Additionally, some offload
-backends, OpenCL for example, require objects of some of these types to be
-passed as individual arguments to the offload kernel.
+necessarily be copied to device memory as if by ``memcpy()``.
 
-An offload kernel consists of an entry point function that declares the
-parameters of the offload kernel and the set of all functions and variables that
-are directly or indirectly used by the entry point function.
+The SYCL kernel object and its data members constitute the parameters of an
+offload kernel. An offload kernel consists of an offload entry point function
+and the set of all functions and variables that are directly or indirectly used
+by the entry point function.
 
-A SYCL kernel invocation function invokes a SYCL kernel on a device by
-performing the following tasks (likely with the help of an offload backend
-like OpenCL):
+A SYCL kernel invocation function is responsible for performing the following
+tasks (likely with the help of an offload backend like OpenCL):
 
 #. Identifying the offload kernel entry point to be used for the SYCL kernel.
 
-#. Decomposing the SYCL kernel object, if necessary, to produce the set of
-   offload kernel arguments required by the offload kernel entry point.
+#. Validating that the SYCL kernel object type and its data members meet the
+   SYCL device copyability and kernel parameter requirements noted above.
 
-#. Copying the offload kernel arguments to device memory.
+#. Copying the SYCL kernel object and any other kernel arguments to device
+   memory including any special handling required for SYCL special types.
 
 #. Initiating execution of the offload kernel entry point.
 
 The offload kernel entry point for a SYCL kernel performs the following tasks:
 
-#. Reconstructing the SYCL kernel object, if necessary, using the offload
-   kernel parameters.
-
-#. Calling the ``operator()`` member function of the (reconstructed) SYCL kernel
-   object.
+#. Calling the ``operator()`` member function of the SYCL kernel object.
 
 The ``sycl_kernel_entry_point`` attribute facilitates or automates these tasks
-by generating the offload kernel entry point, generating a unique symbol name
-for it, synthesizing code for kernel argument decomposition and reconstruction,
-and synthesizing a call to a ``sycl_kernel_launch`` function template
-with the kernel name type, kernel symbol name, and (decomposed) kernel arguments
-passed as template or function arguments.
+by providing generation of an offload kernel entry point with a unique symbol
+name, type checking of kernel argument requirements, and initiation of kernel
+execution via synthesized calls to a ``sycl_kernel_launch`` template.
 
 A function declared with the ``sycl_kernel_entry_point`` attribute specifies
-the parameters and body of the offload entry point function. Consider the
+the parameters and body of an offload entry point function. Consider the
 following call to the ``single_task()`` SYCL kernel invocation function assuming
 an implementation similar to the one shown above.
 
@@ -653,81 +654,65 @@ an implementation similar to the one shown above.
     });
   }
 
-The SYCL kernel object is the result of the lambda expression. It has two
-data members corresponding to the captures of ``sout`` and ``s``. Since one
-of these data members corresponds to a special SYCL type that must be passed
-individually as an offload kernel argument, it is necessary to decompose the
-SYCL kernel object into its constituent parts and pass them individually. An
-offload kernel entry point function will be generated that looks approximately
+The SYCL kernel object is the result of the lambda expression. The call to
+``kernel_entry_point()`` via the call to ``single_task()`` triggers the
+generation of an offload kernel entry point function that looks approximately
 as follows.
 
 .. code-block:: c++
 
-  void sycl-kernel-caller-for-KN(sycl::stream sout, S s) {
-    kernel-type Kernel = { sout, s );
-    Kernel();
+  void sycl-kernel-caller-for-KN(kernel-type kernelFunc) {
+    kernelFunc();
   }
 
 There are a few items worthy of note:
 
-#. The name of the generated function incorporates the SYCL kernel name,
-   ``KN``, that was passed as the ``KernelNameType`` template parameter to
-   ``single_task()`` and eventually provided as the argument to the
-   ``sycl_kernel_entry_point`` attribute. There is a one-to-one correspondence
-   between SYCL kernel names and offload kernel entry points.
-
-#. The parameters and the call to ``Kernel()`` correspond to the definition of
-   ``kernel_entry_point()`` called by ``single_task()`` with the SYCL kernel
-   object argument decomposed and reconstructed.
+#.  ``sycl-kernel-caller-for-KN`` is an exposition only name; the actual name
+    generated for an entry point is an implementation detail and subject to
+    change. However, the name will incorporate the SYCL kernel name, ``KN``,
+    that was passed as the ``KernelName`` template parameter to
+    ``single_task()`` and eventually provided as the argument to the
+    ``sycl_kernel_entry_point`` attribute in order to ensure that a unique
+    name is generated for each entry point. There is a one-to-one correspondence
+    between SYCL kernel names and offload kernel entry points.
 
 #. The SYCL kernel is a lambda closure type and therefore has no name;
    ``kernel-type`` is substituted above and corresponds to the ``KernelType``
    template parameter deduced in the call to ``single_task()``.
-   Lambda types cannot be declared and initialized using the aggregate
-   initialization syntax used above, but the intended behavior should be clear.
 
-#. ``S`` is a device copyable type that does not directly or indirectly contain
-   a data member of a SYCL special type. It therefore does not need to be
-   decomposed into its constituent members to be passed as a kernel argument.
+#. The parameter and the call to ``kernelFunc()`` in the function body
+   correspond to the definition of ``kernel_entry_point()`` as called by
+   ``single_task()``.
 
-#. The depiction of the ``sycl::stream`` parameter as a single self contained
-   kernel parameter is an oversimplification. SYCL special types may require
-   additional decomposition such that the generated function might have three
-   or more parameters depending on how the SYCL library implementation defines
-   these types.
+#. The parameter is type checked for conformance with the SYCL device
+   copyability and kernel parameter requirements.
 
-The call to ``kernel_entry_point()`` by ``single_task()`` is effectively
-replaced with synthesized code that looks approximately as follows.
+Within ``single_task()``, the call to ``kernel_entry_point()`` is effectively
+replaced with a synthesized call to a ''sycl_kernel_launch`` template that
+looks approximately as follows.
 
 .. code-block:: c++
 
-  sycl::stream sout = Kernel.sout;
-  S s = Kernel.s;
-  sycl_kernel_launch<KN>("kernel-symbol-name", sout, s);
+  sycl_kernel_launch<KN>("sycl-kernel-caller-for-KN", kernelFunc);
 
 There are a few items worthy of note:
 
-#. The SYCL kernel object is a lambda closure type and its captures do not
-   have formal names and cannot be accessed using the member access syntax used
-   above, but the intended behavior should be clear.
-
-#. ``kernel-symbol-name`` is substituted for the actual symbol name that would
-   be generated; these names are implementation details subject to change.
-
-#. Lookup for the ``sycl_kernel_launch()`` function template is
-   performed from the (possibly instantiated) location of the definition of
-   ``kernel_entry_point()``. If overload resolution fails, the program is
-   ill-formed. If the selected overload is a non-static member function, then
-   ``this`` is passed for the implicit object parameter.
+#. Lookup for the ``sycl_kernel_launch`` template is performed as if from the
+   body of the (possibly instantiated) definition of ``kernel_entry_point()``.
+   If name lookup or overload resolution fails, the program is ill-formed.
+   If the selected overload is a non-static member function, then ``this`` is
+   passed as the implicit object parameter.
 
 #. Function arguments passed to ``sycl_kernel_launch()`` are passed
-   as if by ``std::forward<X>(x)``.
+   as if by ``std::move(x)``.
 
-#. The ``sycl_kernel_launch()`` function is expected to be provided by
-   the SYCL library implementation. It is responsible for scheduling execution
-   of the generated offload kernel entry point identified by
-   ``kernel-symbol-name`` and copying the (decomposed) kernel arguments to
-   device memory, presumably via an offload backend such as OpenCL.
+#. The ``sycl_kernel_launch`` template is expected to be provided by the SYCL
+   library implementation. It is responsible for copying the kernel arguments
+   to device memory  and for scheduling execution of the generated offload
+   kernel entry point identified by the symbol name passed as the first
+   function argument. ``sycl-kernel-caller-for-KN`` is substituted above for
+   the actual symbol name that would be generated for the offload kernel entry
+   point.
 
 It is not necessary for a function declared with the ``sycl_kernel_entry_point``
 attribute to be called for the offload kernel entry point to be emitted. For
@@ -739,12 +724,11 @@ required for the synthesized call to ``sycl_kernel_launch()`` to occur.
 Functions declared with the ``sycl_kernel_entry_point`` attribute are not
 limited to the simple example shown above. They may have additional template
 parameters, declare additional function parameters, and have complex control
-flow in the function body. Function parameter decomposition and reconstruction
-is performed for all function parameters. The function must abide by the
-language feature restrictions described in section 5.4, "Language restrictions
-for device functions" in the SYCL 2020 specification. If the function is a
-non-static member function, ``this`` shall not be used in a potentially
-evaluated expression.
+flow in the function body. The function must abide by the language feature
+restrictions described in section 5.4, "Language restrictions for device
+functions" in the SYCL 2020 specification. If the function is a non-static
+member function, ``this`` shall not be used in a potentially evaluated
+expression.
   }];
 }
 

>From 793c5801a2a7d54da595a2d3bfb2f5deb54b972d Mon Sep 17 00:00:00 2001
From: Tom Honermann <tom.honermann at intel.com>
Date: Thu, 20 Nov 2025 21:58:36 -0800
Subject: [PATCH 16/29] Added an additional test case to
 sycl-kernel-launch-ms-compat.cpp.

---
 .../SemaSYCL/sycl-kernel-launch-ms-compat.cpp | 43 +++++++++++++++++++
 clang/test/SemaSYCL/sycl-kernel-launch.cpp    |  2 +
 2 files changed, 45 insertions(+)

diff --git a/clang/test/SemaSYCL/sycl-kernel-launch-ms-compat.cpp b/clang/test/SemaSYCL/sycl-kernel-launch-ms-compat.cpp
index 8125ec53fffed..fdcfee3860c76 100644
--- a/clang/test/SemaSYCL/sycl-kernel-launch-ms-compat.cpp
+++ b/clang/test/SemaSYCL/sycl-kernel-launch-ms-compat.cpp
@@ -4,6 +4,7 @@
 // Test Microsoft extensions for lookup of a sycl_kernel_launch member template
 // in a dependent base class.
 
+
 ////////////////////////////////////////////////////////////////////////////////
 // Valid declarations.
 ////////////////////////////////////////////////////////////////////////////////
@@ -41,3 +42,45 @@ namespace ok1 {
   // expected-note at +1 {{in instantiation of member function 'ok1::handler<1>::skep' requested here}}
   template void handler<1>::skep(KT<1>);
 }
+
+
+////////////////////////////////////////////////////////////////////////////////
+// Invalid declarations.
+////////////////////////////////////////////////////////////////////////////////
+
+// A unique kernel name type is required for each declared kernel entry point.
+template<int> struct BADKN;
+
+// A generic kernel object type.
+template<int>
+struct BADKT {
+  void operator()() const;
+};
+
+
+namespace bad1 {
+  template<typename Derived>
+  struct base_handler {
+  private:
+    // expected-note at +3 {{must qualify identifier to find this declaration in dependent base class}}
+    // expected-note at +2 {{declared private here}}
+    template<typename KN, typename... Ts>
+    void sycl_kernel_launch(const char *, Ts...);
+  };
+  template<int N>
+  struct handler : protected base_handler<handler<N>> {
+    // In standard C++, unqualified lookup for sycl_kernel_launch would not
+    // consider dependent base classes. Such lookups are allowed as a Microsoft
+    // compatible extension, but access checks are still performed which makes
+    // this case an error.
+    // expected-warning at +4 {{use of member 'sycl_kernel_launch' found via unqualified lookup into dependent bases of class templates is a Microsoft extension}}
+    // expected-note-re at +2 {{in implicit call to 'sycl_kernel_launch' with template argument 'BADKN<1>' and function arguments (lvalue of type 'const char[{{[0-9]*}}]', xvalue of type 'BADKT<1>') required here}}
+    // expected-error at +2 {{'sycl_kernel_launch' is a private member of 'bad1::base_handler<bad1::handler<1>>'}}
+    [[clang::sycl_kernel_entry_point(BADKN<1>)]]
+    void skep(BADKT<1> k) {
+      k();
+    }
+  };
+  // expected-note at +1 {{in instantiation of member function 'bad1::handler<1>::skep' requested here}}
+  template void handler<1>::skep(BADKT<1>);
+}
diff --git a/clang/test/SemaSYCL/sycl-kernel-launch.cpp b/clang/test/SemaSYCL/sycl-kernel-launch.cpp
index bf1d786e8be26..00f61b8c30ccd 100644
--- a/clang/test/SemaSYCL/sycl-kernel-launch.cpp
+++ b/clang/test/SemaSYCL/sycl-kernel-launch.cpp
@@ -9,6 +9,7 @@
 // synthesized for functions declared with the sycl_kernel_entry_point
 // attribute.
 
+
 ////////////////////////////////////////////////////////////////////////////////
 // Valid declarations.
 ////////////////////////////////////////////////////////////////////////////////
@@ -233,6 +234,7 @@ struct BADKT {
   void operator()() const;
 };
 
+
 // Undeclared sycl_kernel_launch identifier from non-template function.
 namespace bad1 {
   // expected-error at +3 {{use of undeclared identifier 'sycl_kernel_launch'}}

>From 652307ff222542a4a9168788bb64bbe8fd126367 Mon Sep 17 00:00:00 2001
From: Tom Honermann <tom.honermann at intel.com>
Date: Thu, 20 Nov 2025 22:05:00 -0800
Subject: [PATCH 17/29] Fix a style nit noted in code review.

---
 clang/lib/Sema/SemaDecl.cpp | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 5e31cc4a16e73..5862fc063e605 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -16608,9 +16608,8 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, bool IsInstantiation,
       // original function body. An early error return here is not valid; the
       // current declaration context and function scopes must be popped before
       // returning.
-      if (SR.isUsable()) {
+      if (SR.isUsable())
         Body = SR.get();
-      }
     }
   }
 

>From 5bad20faeac51703d4f0294bcca0d5e2743634ff Mon Sep 17 00:00:00 2001
From: Tom Honermann <tom.honermann at intel.com>
Date: Fri, 5 Dec 2025 09:42:16 -0800
Subject: [PATCH 18/29] Addressed code review comments from Mariya and
 corrected a grammar issue in a comment.

---
 clang/lib/Sema/SemaDecl.cpp | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 5862fc063e605..d628e7eed532a 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -16367,13 +16367,13 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D,
     if (!SKEPAttr->isInvalidAttr()) {
       ExprResult LaunchIdExpr =
           SYCL().BuildSYCLKernelLaunchIdExpr(FD, SKEPAttr->getKernelName());
-      if (LaunchIdExpr.isInvalid()) {
-        // Do not mark 'FD' as invalid. Name lookup failure for
-        // 'sycl_kernel_launch' is treated as an error in the definition of
-        // 'FD'; treating it as an error of the declaration would affect
-        // overload resolution.
-      }
-
+      // Do not mark 'FD' as invalid if construction of `LaunchIDExpr` produces
+      // an invalid result. Name lookup failure for 'sycl_kernel_launch' is
+      // treated as an error in the definition of 'FD'; treating it as an error
+      // of the declaration would affect overload resolution which would
+      // potentially result in additional errors. If construction of
+      // 'LaunchIDExpr' failed, then 'SYCLKernelLaunchIdExpr' will be assigned
+      // a null pointer value below; that is expected.
       getCurFunction()->SYCLKernelLaunchIdExpr = LaunchIdExpr.get();
     }
   }
@@ -16588,7 +16588,7 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, bool IsInstantiation,
       StmtResult SR;
       if (FD->isTemplateInstantiation()) {
         // The function body should already be a SYCLKernelCallStmt in this
-        // case, but might not be if errors previous occurred.
+        // case, but might not be if there were previous errors.
         SR = Body;
       } else if (!getCurFunction()->SYCLKernelLaunchIdExpr) {
         // If name lookup for a template named sycl_kernel_launch failed

>From 7368b3ca6952dcc47ab4b464a6195d7162a98dfc Mon Sep 17 00:00:00 2001
From: Tom Honermann <tom.honermann at intel.com>
Date: Fri, 5 Dec 2025 10:52:48 -0800
Subject: [PATCH 19/29] Added code generation tests for exception handling.

---
 clang/include/clang/Basic/AttrDocs.td         |  6 ++
 .../sycl-kernel-entry-point-exceptions.cpp    | 95 +++++++++++++++++++
 2 files changed, 101 insertions(+)
 create mode 100644 clang/test/CodeGenSYCL/sycl-kernel-entry-point-exceptions.cpp

diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td
index 4885d21ddd57f..907b8029be3e1 100644
--- a/clang/include/clang/Basic/AttrDocs.td
+++ b/clang/include/clang/Basic/AttrDocs.td
@@ -721,6 +721,12 @@ functions, an ODR-use is not required; the offload kernel entry point will be
 emitted if the function is defined. In any case, a call to the function is
 required for the synthesized call to ``sycl_kernel_launch()`` to occur.
 
+A function declared with the ``sycl_kernel_entry_point`` attribute may include
+an exception specification. If a non-throwing exception specification is
+present, an exception propagating from the implicit call to the
+``sycl_kernel_launch`` template will result in a call to ``std::terminate()``.
+Otherwise, such an exception will propagate normally.
+
 Functions declared with the ``sycl_kernel_entry_point`` attribute are not
 limited to the simple example shown above. They may have additional template
 parameters, declare additional function parameters, and have complex control
diff --git a/clang/test/CodeGenSYCL/sycl-kernel-entry-point-exceptions.cpp b/clang/test/CodeGenSYCL/sycl-kernel-entry-point-exceptions.cpp
new file mode 100644
index 0000000000000..8fe7a148a2f61
--- /dev/null
+++ b/clang/test/CodeGenSYCL/sycl-kernel-entry-point-exceptions.cpp
@@ -0,0 +1,95 @@
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++17 -fcxx-exceptions -fexceptions -fsycl-is-host -emit-llvm -o - %s | FileCheck %s
+
+// Validate generation of exception handling code for functions declared
+// with the sycl_kernel_entry_point attribute that implicitly call a
+// sycl_kernel_launch function that may throw an exception. Exception
+// handling is not relevant for the generated offload kernel entry point
+// function, so device compilation is intentionally not exercised.
+
+// A unique kernel name type is required for each declared kernel entry point.
+template<int> struct KN;
+
+// A generic kernel object type.
+template<int, int = 0>
+struct KT {
+  void operator()() const;
+};
+
+
+// Validate that exception handling instructions are omitted when a
+// potentially throwing sycl_kernel_entry_point attributed function
+// calls a potentially throwing sycl_kernel_launch function (a thrown
+// exception will propagate with no explicit handling required).
+namespace ns1 {
+  template<typename KN, typename... Ts>
+  void sycl_kernel_launch(const char *, Ts...);
+  [[clang::sycl_kernel_entry_point(KN<1>)]]
+  void skep(KT<1> k) {
+    k();
+  }
+}
+// CHECK: ; Function Attrs: mustprogress noinline optnone
+// CHECK: define dso_local void @_ZN3ns14skepE2KTILi1ELi0EE() #{{[0-9]+}} {
+// CHECK:   call void @_ZN3ns118sycl_kernel_launchI2KNILi1EEJ2KTILi1ELi0EEEEEvPKcDpT0_(ptr noundef @.str)
+// CHECK:   ret void
+// CHECK: }
+
+
+// Validate that exception handling instructions are emitted when a
+// non-throwing sycl_kernel_entry_point attributed function calls
+// a potentially throwing sycl_kernel_launch function.
+namespace ns2 {
+  template<typename KN, typename... Ts>
+  void sycl_kernel_launch(const char *, Ts...);
+  [[clang::sycl_kernel_entry_point(KN<2>)]]
+  void skep(KT<2> k) noexcept {
+    k();
+  }
+}
+// CHECK: ; Function Attrs: mustprogress noinline nounwind optnone
+// CHECK: define dso_local void @_ZN3ns24skepE2KTILi2ELi0EE() #{{[0-9]+}} personality ptr @__gxx_personality_v0 {
+// CHECK:   invoke void @_ZN3ns218sycl_kernel_launchI2KNILi2EEJ2KTILi2ELi0EEEEEvPKcDpT0_(ptr noundef @.str.1)
+// CHECK:           to label %invoke.cont unwind label %terminate.lpad
+// CHECK: invoke.cont:
+// CHECK:   ret void
+// CHECK: terminate.lpad:
+// CHECK:   call void @__clang_call_terminate(ptr %1) #{{[0-9]+}}
+// CHECK:   unreachable
+// CHECK: }
+
+
+// Validate that exception handling instructions are omitted when a
+// potentially throwing sycl_kernel_entry_point attributed function
+// calls a non-throwing sycl_kernel_launch function (a thrown
+// exception will terminate within sycl_kernel_launch).
+namespace ns3 {
+  template<typename KN, typename... Ts>
+  void sycl_kernel_launch(const char *, Ts...) noexcept;
+  [[clang::sycl_kernel_entry_point(KN<3>)]]
+  void skep(KT<3> k) {
+    k();
+  }
+}
+// CHECK: ; Function Attrs: mustprogress noinline nounwind optnone
+// CHECK: define dso_local void @_ZN3ns34skepE2KTILi3ELi0EE() #{{[0-9]+}} {
+// CHECK:   call void @_ZN3ns318sycl_kernel_launchI2KNILi3EEJ2KTILi3ELi0EEEEEvPKcDpT0_(ptr noundef @.str.2)
+// CHECK:   ret void
+// CHECK: }
+
+
+// Validate that exception handling instructions are omitted when a
+// non-throwing sycl_kernel_entry_point attributed function calls a
+// non-throwing sycl_kernel_launch function.
+namespace ns4 {
+  template<typename KN, typename... Ts>
+  void sycl_kernel_launch(const char *, Ts...) noexcept;
+  [[clang::sycl_kernel_entry_point(KN<4>)]]
+  void skep(KT<4> k) noexcept {
+    k();
+  }
+}
+// CHECK: ; Function Attrs: mustprogress noinline nounwind optnone
+// CHECK: define dso_local void @_ZN3ns44skepE2KTILi4ELi0EE() #{{[0-9]+}} {
+// CHECK:   call void @_ZN3ns418sycl_kernel_launchI2KNILi4EEJ2KTILi4ELi0EEEEEvPKcDpT0_(ptr noundef @.str.3)
+// CHECK:   ret void
+// CHECK: }

>From c7d56e5a5d16726a0816a09281dd803a8d77dbd0 Mon Sep 17 00:00:00 2001
From: Tom Honermann <tom.honermann at intel.com>
Date: Wed, 11 Feb 2026 08:56:38 -0800
Subject: [PATCH 20/29] Issue a deferred diagnostic for use of a
 sycl_kernel_entry_point attributed function in a device function.

The diagnostics issued for this situation are not ideal; the same errors might
be diagnosed multiple times due to limitations or defects in the implementation
of deferred diagnostics. The following issue tracks improvements.
- https://github.com/llvm/llvm-project/issues/180638.

The diagnostic should suffice to prevent a sycl_kernel_entry_point attributed
function definition from being emitted during device compilation. However, if
such emission does somehow occur, this change ensures that the definition
will include an unreachable instruction.
---
 .../clang/Basic/DiagnosticSemaKinds.td        |   5 +-
 clang/include/clang/Sema/Sema.h               |   3 +-
 clang/include/clang/Sema/SemaSYCL.h           |   4 +
 clang/lib/CodeGen/CodeGenSYCL.cpp             |  21 +--
 clang/lib/Sema/SemaDecl.cpp                   |   4 +-
 clang/lib/Sema/SemaExpr.cpp                   |   3 +
 clang/lib/Sema/SemaSYCL.cpp                   |  43 +++++-
 ...-kernel-entry-point-attr-appertainment.cpp |   6 +-
 ...kernel-entry-point-attr-device-odr-use.cpp | 142 ++++++++++++++++++
 .../sycl-kernel-entry-point-attr-this.cpp     |   2 +-
 10 files changed, 208 insertions(+), 25 deletions(-)
 create mode 100644 clang/test/SemaSYCL/sycl-kernel-entry-point-attr-device-odr-use.cpp

diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 22b32631696e9..06ffc620865ef 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -13289,7 +13289,10 @@ def note_sycl_kernel_launch_lookup_here : Note<
   " here">;
 def note_sycl_kernel_launch_overload_resolution_here : Note<
   "in implicit call to 'sycl_kernel_launch' with template argument %0 and"
- " function arguments %1 required here">;
+  " function arguments %1 required here">;
+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_cuda_maxclusterrank_sm_90 : Warning<
   "maxclusterrank requires sm_90 or higher, CUDA arch provided: %0, ignoring "
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index f30b8d15487a3..c3699ef90c1bd 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -1414,7 +1414,8 @@ class Sema final : public SemaBase {
 
   /// Diagnostics that are emitted only if we discover that the given function
   /// must be codegen'ed.  Because handling these correctly adds overhead to
-  /// compilation, this is currently only enabled for CUDA compilations.
+  /// compilation, this is currently only used for offload languages like CUDA,
+  /// OpenMP, and SYCL.
   SemaDiagnosticBuilder::DeferredDiagnosticsType DeviceDeferredDiags;
 
   /// CurContext - This is the current declaration context of parsing.
diff --git a/clang/include/clang/Sema/SemaSYCL.h b/clang/include/clang/Sema/SemaSYCL.h
index 5018c1093b5c6..7703185cacca9 100644
--- a/clang/include/clang/Sema/SemaSYCL.h
+++ b/clang/include/clang/Sema/SemaSYCL.h
@@ -64,6 +64,10 @@ class SemaSYCL : public SemaBase {
   void handleKernelAttr(Decl *D, const ParsedAttr &AL);
   void handleKernelEntryPointAttr(Decl *D, const ParsedAttr &AL);
 
+  /// Issues a deferred diagnostic if use of the declaration designated
+  /// by 'D' is invalid in a device context.
+  void CheckDeviceUseOfDecl(NamedDecl *D, SourceLocation Loc);
+
   void CheckSYCLExternalFunctionDecl(FunctionDecl *FD);
   void CheckSYCLEntryPointFunctionDecl(FunctionDecl *FD);
 
diff --git a/clang/lib/CodeGen/CodeGenSYCL.cpp b/clang/lib/CodeGen/CodeGenSYCL.cpp
index 5ad5671250a92..74c1a68f1526d 100644
--- a/clang/lib/CodeGen/CodeGenSYCL.cpp
+++ b/clang/lib/CodeGen/CodeGenSYCL.cpp
@@ -19,17 +19,18 @@ using namespace CodeGen;
 
 void CodeGenFunction::EmitSYCLKernelCallStmt(const SYCLKernelCallStmt &S) {
   if (getLangOpts().SYCLIsDevice) {
-    // A sycl_kernel_entry_point attributed function is unlikely to be emitted
-    // during device compilation, but might be if it is ODR-used from device
-    // code that is emitted. In these cases, the function is emitted with an
-    // empty body; the original body is emitted in the offload kernel entry
-    // point and the synthesized kernel launch code is only relevant for host
-    // compilation.
-    return;
+    // A definition for a sycl_kernel_entry_point attributed function should
+    // never be emitted during device compilation; a diagnostic should be
+    // issued for any such ODR-use.
+    assert(false && "Attempt to emit a sycl_kernel_entry_point function during "
+                    "device compilation");
+    // However, if a definition is somehow emitted, emit an unreachable
+    // instruction to thwart any attempted execution.
+    EmitUnreachable(S.getBeginLoc());
+  } else {
+    assert(getLangOpts().SYCLIsHost);
+    EmitStmt(S.getKernelLaunchStmt());
   }
-
-  assert(getLangOpts().SYCLIsHost);
-  EmitStmt(S.getKernelLaunchStmt());
 }
 
 static void SetSYCLKernelAttributes(llvm::Function *Fn, CodeGenFunction &CGF) {
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index d628e7eed532a..879039ec53ed0 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -21080,7 +21080,9 @@ Sema::FunctionEmissionStatus Sema::getEmissionStatus(const FunctionDecl *FD,
 
   // SYCL functions can be template, so we check if they have appropriate
   // attribute prior to checking if it is a template.
-  if (LangOpts.SYCLIsDevice && FD->hasAttr<SYCLKernelAttr>())
+  if (LangOpts.SYCLIsDevice && (FD->hasAttr<SYCLKernelAttr>() ||
+                                FD->hasAttr<SYCLKernelEntryPointAttr>() ||
+                                FD->hasAttr<SYCLExternalAttr>()))
     return FunctionEmissionStatus::Emitted;
 
   // Templates are emitted when they're instantiated.
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index fce803fcdd395..f8e11a6f1b7b1 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -406,6 +406,9 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, ArrayRef<SourceLocation> Locs,
           targetDiag(*Locs.begin(), diag::err_thread_unsupported);
   }
 
+  if (LangOpts.SYCLIsDevice && isa<FunctionDecl>(D))
+    SYCL().CheckDeviceUseOfDecl(D, Loc);
+
   return false;
 }
 
diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp
index f5c2418076e6e..8745eacabb0cf 100644
--- a/clang/lib/Sema/SemaSYCL.cpp
+++ b/clang/lib/Sema/SemaSYCL.cpp
@@ -31,14 +31,24 @@ Sema::SemaDiagnosticBuilder SemaSYCL::DiagIfDeviceCode(SourceLocation Loc,
                                                        unsigned DiagID) {
   assert(getLangOpts().SYCLIsDevice &&
          "Should only be called during SYCL compilation");
-  FunctionDecl *FD = dyn_cast<FunctionDecl>(SemaRef.getCurLexicalContext());
-  SemaDiagnosticBuilder::Kind DiagKind = [this, FD] {
-    if (!FD)
-      return SemaDiagnosticBuilder::K_Nop;
-    if (SemaRef.getEmissionStatus(FD) == Sema::FunctionEmissionStatus::Emitted)
-      return SemaDiagnosticBuilder::K_ImmediateWithCallStack;
-    return SemaDiagnosticBuilder::K_Deferred;
-  }();
+  SemaDiagnosticBuilder::Kind DiagKind = SemaDiagnosticBuilder::K_Nop;
+  FunctionDecl *FD = SemaRef.getCurFunctionDecl(/*AllowLambda=*/true);
+  if (FD) {
+    Sema::FunctionEmissionStatus FES = SemaRef.getEmissionStatus(FD);
+    switch (FES) {
+    case Sema::FunctionEmissionStatus::Emitted:
+      DiagKind = SemaDiagnosticBuilder::K_ImmediateWithCallStack;
+      break;
+    case Sema::FunctionEmissionStatus::Unknown:
+    case Sema::FunctionEmissionStatus::TemplateDiscarded:
+      DiagKind = SemaDiagnosticBuilder::K_Deferred;
+      break;
+    case Sema::FunctionEmissionStatus::OMPDiscarded:
+      llvm_unreachable("OMPDiscarded unexpected in SYCL device compilation");
+    case Sema::FunctionEmissionStatus::CUDADiscarded:
+      llvm_unreachable("CUDADiscarded unexpected in SYCL device compilation");
+    }
+  }
   return SemaDiagnosticBuilder(DiagKind, Loc, DiagID, FD, SemaRef);
 }
 
@@ -211,6 +221,23 @@ void SemaSYCL::handleKernelEntryPointAttr(Decl *D, const ParsedAttr &AL) {
                  SYCLKernelEntryPointAttr(SemaRef.Context, AL, TSI));
 }
 
+void SemaSYCL::CheckDeviceUseOfDecl(NamedDecl *D, SourceLocation Loc) {
+  assert(getLangOpts().SYCLIsDevice &&
+         "Should only be called during SYCL compilation");
+
+  // Function declarations with the sycl_kernel_entry_point attribute cannot
+  // be ODR-used in a potentially evaluated context.
+  if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+    if (const auto *SKEPAttr = FD->getAttr<SYCLKernelEntryPointAttr>()) {
+      if (SemaRef.currentEvaluationContext().isPotentiallyEvaluated()) {
+        DiagIfDeviceCode(Loc, diag::err_sycl_entry_point_device_use)
+            << FD << SKEPAttr;
+        DiagIfDeviceCode(SKEPAttr->getLocation(), diag::note_attribute) << FD;
+      }
+    }
+  }
+}
+
 // Given a potentially qualified type, SourceLocationForUserDeclaredType()
 // returns the source location of the canonical declaration of the unqualified
 // desugared user declared type, if any. For non-user declared types, an
diff --git a/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-appertainment.cpp b/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-appertainment.cpp
index a17e4c1d1be0a..45da8c71348b2 100644
--- a/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-appertainment.cpp
+++ b/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-appertainment.cpp
@@ -1,9 +1,9 @@
 // RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++17 -fsyntax-only -fsycl-is-host -fcxx-exceptions -verify %s
-// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++17 -fsyntax-only -fsycl-is-device -verify %s
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++17 -fsyntax-only -fsycl-is-device -fcxx-exceptions -verify %s
 // RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++20 -fsyntax-only -fsycl-is-host -fcxx-exceptions -verify %s
-// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++20 -fsyntax-only -fsycl-is-device -verify %s
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++20 -fsyntax-only -fsycl-is-device -fcxx-exceptions -verify %s
 // RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++23 -fsyntax-only -fsycl-is-host -fcxx-exceptions -verify %s
-// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++23 -fsyntax-only -fsycl-is-device -verify %s
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++23 -fsyntax-only -fsycl-is-device -fcxx-exceptions -verify %s
 
 // These tests validate appertainment for the sycl_kernel_entry_point attribute.
 
diff --git a/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-device-odr-use.cpp b/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-device-odr-use.cpp
new file mode 100644
index 0000000000000..1aa48c739c043
--- /dev/null
+++ b/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-device-odr-use.cpp
@@ -0,0 +1,142 @@
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++17 -fsycl-is-host -verify=host %s
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++17 -fsycl-is-device -verify=device %s
+
+// These tests validate that a diagnostic is issued if a function declared with
+// the sycl_kernel_entry_point attribute is ODR-used from code that is emitted
+// during device compilation. Such uses are ill-formed because such functions
+// are used to define an offload kernel entry point function; they aren't
+// available for ordinary function use.
+
+// host-no-diagnostics
+
+// Emulate inclusion of <typeinfo>.
+namespace std {
+struct type_info {
+  virtual ~type_info();
+};
+} // namespace std
+
+// A generic kernel launch function.
+template<typename KernelName, typename... Ts>
+void sycl_kernel_launch(const char *, Ts...) {}
+
+// A kernel name type template.
+template<int> struct KN;
+
+// SYCL kernel entry point functions. These are used to both trigger the
+// emission of a function during device compilation (but not during host
+// compilation) and to trigger a diagnostic if ODR-used from a function
+// emitted during device compilation.
+// device-note at +1 4 {{attribute is here}}
+[[clang::sycl_kernel_entry_point(KN<1>)]]
+void skep();
+struct SKL {
+  // device-note at +1 6 {{attribute is here}}
+  [[clang::sycl_kernel_entry_point(KN<2>)]]
+  void mskep();
+  // device-note at +1 6 {{attribute is here}}
+  [[clang::sycl_kernel_entry_point(KN<3>)]]
+  static void smskep();
+  // device-note at +1 2 {{attribute is here}}
+  [[clang::sycl_kernel_entry_point(KN<4>)]]
+  void operator()() const;
+};
+
+// A function that is emitted on the device due to usage reachable from a
+// SYCL kernel entry point function. ODR-uses of sycl_kernel_entry_point
+// attributed functions within this function require a diagnostic during
+// device compilation.
+void df() {
+  // Not ODR-uses; ok.
+  decltype(&skep) p1 = nullptr;
+  decltype(&SKL::mskep) p2 = nullptr;
+  decltype(&SKL::smskep) p3 = nullptr;
+
+  // Not ODR-uses; ok.
+  (void)noexcept(skep());
+  (void)noexcept(SKL{}.mskep());
+  (void)noexcept(SKL::smskep());
+
+  // Not ODR-uses; ok.
+  (void)typeid(&skep);
+  (void)typeid(&SKL::mskep);
+  (void)typeid(&SKL::smskep);
+
+  // device-error at +1 2 {{function 'skep' cannot be used in device code because it is declared with the 'clang::sycl_kernel_entry_point' attribute}}
+  skep();
+  // device-error at +1 2 {{function 'mskep' cannot be used in device code because it is declared with the 'clang::sycl_kernel_entry_point' attribute}}
+  SKL{}.mskep();
+  // device-error at +1 2 {{function 'smskep' cannot be used in device code because it is declared with the 'clang::sycl_kernel_entry_point' attribute}}
+  SKL::smskep();
+
+  // device-error at +1 2 {{function 'skep' cannot be used in device code because it is declared with the 'clang::sycl_kernel_entry_point' attribute}}
+  (void)&skep;
+  // device-error at +1 2 {{function 'mskep' cannot be used in device code because it is declared with the 'clang::sycl_kernel_entry_point' attribute}}
+  (void)&SKL::mskep;
+  // device-error at +1 2 {{function 'smskep' cannot be used in device code because it is declared with the 'clang::sycl_kernel_entry_point' attribute}}
+  (void)&SKL::smskep;
+
+  SKL sklo;
+  // device-error at +1 2 {{function 'operator()' cannot be used in device code because it is declared with the 'clang::sycl_kernel_entry_point' attribute}}
+  sklo();
+}
+
+// device-note at +1 5 {{attribute is here}}
+[[clang::sycl_kernel_entry_point(KN<1>)]]
+void skep() {
+  // device-note at +1 {{called by 'skep'}}
+  df();
+  // device-error at +1 {{function 'skep' cannot be used in device code because it is declared with the 'clang::sycl_kernel_entry_point' attribute}}
+  skep();
+  // device-error at +1 2 {{function 'mskep' cannot be used in device code because it is declared with the 'clang::sycl_kernel_entry_point' attribute}}
+  SKL{}.mskep();
+  // device-error at +1 {{function 'smskep' cannot be used in device code because it is declared with the 'clang::sycl_kernel_entry_point' attribute}}
+  SKL::smskep();
+}
+
+// device-note at +1 7 {{attribute is here}}
+[[clang::sycl_kernel_entry_point(KN<2>)]]
+void SKL::mskep() {
+  df();
+  // device-error at +1 {{function 'skep' cannot be used in device code because it is declared with the 'clang::sycl_kernel_entry_point' attribute}}
+  skep();
+  // device-error at +1 2 {{function 'mskep' cannot be used in device code because it is declared with the 'clang::sycl_kernel_entry_point' attribute}}
+  SKL{}.mskep();
+  // device-error at +1 {{function 'smskep' cannot be used in device code because it is declared with the 'clang::sycl_kernel_entry_point' attribute}}
+  SKL::smskep();
+}
+
+// device-note at +1 3 {{attribute is here}}
+[[clang::sycl_kernel_entry_point(KN<3>)]]
+void SKL::smskep() {
+  df();
+  // device-error at +1 {{function 'skep' cannot be used in device code because it is declared with the 'clang::sycl_kernel_entry_point' attribute}}
+  skep();
+  // device-error at +1 2 {{function 'mskep' cannot be used in device code because it is declared with the 'clang::sycl_kernel_entry_point' attribute}}
+  SKL{}.mskep();
+  // device-error at +1 {{function 'smskep' cannot be used in device code because it is declared with the 'clang::sycl_kernel_entry_point' attribute}}
+  SKL::smskep();
+}
+
+[[clang::sycl_kernel_entry_point(KN<4>)]]
+void SKL::operator()() const {
+  df();
+  // device-error at +1 {{function 'skep' cannot be used in device code because it is declared with the 'clang::sycl_kernel_entry_point' attribute}}
+  skep();
+  // device-error at +1 2 {{function 'mskep' cannot be used in device code because it is declared with the 'clang::sycl_kernel_entry_point' attribute}}
+  SKL{}.mskep();
+  // device-error at +1 {{function 'smskep' cannot be used in device code because it is declared with the 'clang::sycl_kernel_entry_point' attribute}}
+  SKL::smskep();
+}
+
+[[clang::sycl_external]]
+void sedf() {
+  // device-note at +1 {{called by 'sedf'}}
+  df();
+  // device-error at +1 {{function 'skep' cannot be used in device code because it is declared with the 'clang::sycl_kernel_entry_point' attribute}}
+  skep();
+  // device-error at +1 {{function 'mskep' cannot be used in device code because it is declared with the 'clang::sycl_kernel_entry_point' attribute}}
+  SKL{}.mskep();
+  // device-error at +1 {{function 'smskep' cannot be used in device code because it is declared with the 'clang::sycl_kernel_entry_point' attribute}}
+  SKL::smskep();
+}
diff --git a/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-this.cpp b/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-this.cpp
index c9ab242754899..2112733b41fc6 100644
--- a/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-this.cpp
+++ b/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-this.cpp
@@ -22,7 +22,7 @@ struct type_info {
 };
 } // namespace std
 
-// A generic kernell launch function.
+// A generic kernel launch function.
 template<typename KernelName, typename... Ts>
 void sycl_kernel_launch(const char *, Ts...) {}
 

>From b2591cd60a74d738bbeccd880c1a212668880fde Mon Sep 17 00:00:00 2001
From: Tom Honermann <tom.honermann at intel.com>
Date: Wed, 11 Feb 2026 09:10:06 -0800
Subject: [PATCH 21/29] Rename printCallArgsValueCategoryAndType to
 convertCallArgsValueCategoryAndTypeToString.

---
 clang/lib/Sema/SemaTemplateInstantiate.cpp | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index 3e70eb80fcd22..67d724491efea 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -900,7 +900,8 @@ static std::string convertCallArgsToString(Sema &S,
 }
 
 static std::string
-printCallArgsValueCategoryAndType(Sema &S, llvm::ArrayRef<const Expr *> Args) {
+convertCallArgsValueCategoryAndTypeToString(Sema &S,
+                                            llvm::ArrayRef<const Expr *> Args) {
   std::string Result;
   llvm::raw_string_ostream OS(Result);
   llvm::ListSeparator Comma;
@@ -1300,7 +1301,7 @@ void Sema::PrintInstantiationStack(InstantiationContextDiagFuncRef DiagFunc) {
       DiagFunc(SKEPAttr->getLocation(),
                PDiag(diag::note_sycl_kernel_launch_overload_resolution_here)
                    << SKEPAttr->getKernelName()
-                   << printCallArgsValueCategoryAndType(
+                   << convertCallArgsValueCategoryAndTypeToString(
                           *this, llvm::ArrayRef(Active->CallArgs,
                                                 Active->NumCallArgs)));
       break;

>From 0dd10da82183f8744b1f108334298346f07d683d Mon Sep 17 00:00:00 2001
From: Tom Honermann <tom.honermann at intel.com>
Date: Wed, 11 Feb 2026 11:14:09 -0800
Subject: [PATCH 22/29] Added a note to errors issued for implicit calls to
 sycl_kernel_launch that such errors indicate a defect in the SYCL runtime
 headers.

---
 .../clang/Basic/DiagnosticSemaKinds.td        |  3 +
 clang/lib/Sema/SemaTemplateInstantiate.cpp    |  2 +
 .../SemaSYCL/sycl-kernel-launch-ms-compat.cpp |  6 +-
 clang/test/SemaSYCL/sycl-kernel-launch.cpp    | 57 ++++++++++++-------
 4 files changed, 47 insertions(+), 21 deletions(-)

diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 06ffc620865ef..65e2018980382 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -13284,6 +13284,9 @@ def err_sycl_entry_point_return_type : Error<
 def err_sycl_entry_point_deduced_return_type : Error<
   "the %0 attribute only applies to functions with a non-deduced 'void' return"
   " type">;
+def note_sycl_runtime_defect : Note<
+  "this error is due to a defect in SYCL runtime header files; please report"
+  " this problem to your SYCL runtime provider">;
 def note_sycl_kernel_launch_lookup_here : Note<
   "in implicit call to 'sycl_kernel_launch' with template argument %0 required"
   " here">;
diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index 67d724491efea..4cbcc7c7cdc70 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -1287,6 +1287,7 @@ void Sema::PrintInstantiationStack(InstantiationContextDiagFuncRef DiagFunc) {
       assert(SKEPAttr && "Missing sycl_kernel_entry_point attribute");
       assert(!SKEPAttr->isInvalidAttr() &&
              "sycl_kernel_entry_point attribute is invalid");
+      DiagFunc(SKEPAttr->getLocation(), PDiag(diag::note_sycl_runtime_defect));
       DiagFunc(SKEPAttr->getLocation(),
                PDiag(diag::note_sycl_kernel_launch_lookup_here)
                    << SKEPAttr->getKernelName());
@@ -1298,6 +1299,7 @@ void Sema::PrintInstantiationStack(InstantiationContextDiagFuncRef DiagFunc) {
       assert(SKEPAttr && "Missing sycl_kernel_entry_point attribute");
       assert(!SKEPAttr->isInvalidAttr() &&
              "sycl_kernel_entry_point attribute is invalid");
+      DiagFunc(SKEPAttr->getLocation(), PDiag(diag::note_sycl_runtime_defect));
       DiagFunc(SKEPAttr->getLocation(),
                PDiag(diag::note_sycl_kernel_launch_overload_resolution_here)
                    << SKEPAttr->getKernelName()
diff --git a/clang/test/SemaSYCL/sycl-kernel-launch-ms-compat.cpp b/clang/test/SemaSYCL/sycl-kernel-launch-ms-compat.cpp
index fdcfee3860c76..12eed1bbe29ec 100644
--- a/clang/test/SemaSYCL/sycl-kernel-launch-ms-compat.cpp
+++ b/clang/test/SemaSYCL/sycl-kernel-launch-ms-compat.cpp
@@ -32,7 +32,8 @@ namespace ok1 {
     // A warning is issued because, in standard C++, unqualified lookup for
     // sycl_kernel_launch would not consider dependent base classes. Such
     // lookups are allowed as a Microsoft compatible extension.
-    // expected-warning at +3 {{use of member 'sycl_kernel_launch' found via unqualified lookup into dependent bases of class templates is a Microsoft extension}}
+    // expected-warning at +4 {{use of member 'sycl_kernel_launch' found via unqualified lookup into dependent bases of class templates is a Microsoft extension}}
+    // expected-note at +2 {{this error is due to a defect in SYCL runtime header files; please report this problem to your SYCL runtime provider}}
     // expected-note-re at +1 {{in implicit call to 'sycl_kernel_launch' with template argument 'KN<1>' and function arguments (lvalue of type 'const char[{{[0-9]*}}]', xvalue of type 'KT<1>') required here}}
     [[clang::sycl_kernel_entry_point(KN<1>)]]
     void skep(KT<1> k) {
@@ -73,7 +74,8 @@ namespace bad1 {
     // consider dependent base classes. Such lookups are allowed as a Microsoft
     // compatible extension, but access checks are still performed which makes
     // this case an error.
-    // expected-warning at +4 {{use of member 'sycl_kernel_launch' found via unqualified lookup into dependent bases of class templates is a Microsoft extension}}
+    // expected-warning at +5 {{use of member 'sycl_kernel_launch' found via unqualified lookup into dependent bases of class templates is a Microsoft extension}}
+    // expected-note at +3 {{this error is due to a defect in SYCL runtime header files; please report this problem to your SYCL runtime provider}}
     // expected-note-re at +2 {{in implicit call to 'sycl_kernel_launch' with template argument 'BADKN<1>' and function arguments (lvalue of type 'const char[{{[0-9]*}}]', xvalue of type 'BADKT<1>') required here}}
     // expected-error at +2 {{'sycl_kernel_launch' is a private member of 'bad1::base_handler<bad1::handler<1>>'}}
     [[clang::sycl_kernel_entry_point(BADKN<1>)]]
diff --git a/clang/test/SemaSYCL/sycl-kernel-launch.cpp b/clang/test/SemaSYCL/sycl-kernel-launch.cpp
index 00f61b8c30ccd..dfd55a2424248 100644
--- a/clang/test/SemaSYCL/sycl-kernel-launch.cpp
+++ b/clang/test/SemaSYCL/sycl-kernel-launch.cpp
@@ -237,7 +237,8 @@ struct BADKT {
 
 // Undeclared sycl_kernel_launch identifier from non-template function.
 namespace bad1 {
-  // expected-error at +3 {{use of undeclared identifier 'sycl_kernel_launch'}}
+  // expected-error at +4 {{use of undeclared identifier 'sycl_kernel_launch'}}
+  // expected-note at +2 {{this error is due to a defect in SYCL runtime header files; please report this problem to your SYCL runtime provider}}
   // expected-note-re at +1 {{in implicit call to 'sycl_kernel_launch' with template argument 'BADKN<1>' and function arguments (lvalue of type 'const char[{{[0-9]*}}]', xvalue of type 'BADKT<1>') required here}}
   [[clang::sycl_kernel_entry_point(BADKN<1>)]]
   void skep(BADKT<1> k) {
@@ -247,7 +248,8 @@ namespace bad1 {
 
 // Undeclared sycl_kernel_launch identifier from function template.
 namespace bad2 {
-  // expected-error at +4 {{use of undeclared identifier 'sycl_kernel_launch'}}
+  // expected-error at +5 {{use of undeclared identifier 'sycl_kernel_launch'}}
+  // expected-note at +3 {{this error is due to a defect in SYCL runtime header files; please report this problem to your SYCL runtime provider}}
   // expected-note-re at +2 {{in implicit call to 'sycl_kernel_launch' with template argument 'BADKN<2>' and function arguments (lvalue of type 'const char[{{[0-9]*}}]', xvalue of type 'BADKT<2>') required here}}
   template<typename KN, typename KT>
   [[clang::sycl_kernel_entry_point(KN)]]
@@ -262,7 +264,8 @@ namespace bad2 {
 namespace bad3 {
   // expected-note at +1 {{declared as a non-template here}}
   void sycl_kernel_launch(const char *, BADKT<3>);
-  // expected-error at +3 {{'sycl_kernel_launch' does not refer to a template}}
+  // expected-error at +4 {{'sycl_kernel_launch' does not refer to a template}}
+  // expected-note at +2 {{this error is due to a defect in SYCL runtime header files; please report this problem to your SYCL runtime provider}}
   // expected-note at +1 {{in implicit call to 'sycl_kernel_launch' with template argument 'BADKN<3>' required here}}
   [[clang::sycl_kernel_entry_point(BADKN<3>)]]
   void skep(BADKT<3> k) {
@@ -275,7 +278,8 @@ namespace bad4 {
   // expected-note at +2 {{candidate function template not viable: requires 2 arguments, but 1 was provided}}
   template<typename KN, typename KT>
   void sycl_kernel_launch(const char *, KT);
-  // expected-error at +4 {{no matching function for call to 'sycl_kernel_launch'}}
+  // expected-error at +5 {{no matching function for call to 'sycl_kernel_launch'}}
+  // expected-note at +3 {{this error is due to a defect in SYCL runtime header files; please report this problem to your SYCL runtime provider}}
   // expected-note-re at +2 {{in implicit call to 'sycl_kernel_launch' with template argument 'BADKN<4>' and function arguments (lvalue of type 'const char[{{[0-9]*}}]') required here}}
   template<typename KN>
   [[clang::sycl_kernel_entry_point(KN)]]
@@ -289,7 +293,8 @@ namespace bad5 {
   // expected-note at +2 {{candidate function template not viable: requires 2 arguments, but 3 were provided}}
   template<typename KN, typename KT>
   void sycl_kernel_launch(const char *, KT);
-  // expected-error at +4 {{no matching function for call to 'sycl_kernel_launch'}}
+  // expected-error at +5 {{no matching function for call to 'sycl_kernel_launch'}}
+  // expected-note at +3 {{this error is due to a defect in SYCL runtime header files; please report this problem to your SYCL runtime provider}}
   // expected-note-re at +2 {{in implicit call to 'sycl_kernel_launch' with template argument 'BADKN<5>' and function arguments (lvalue of type 'const char[{{[0-9]*}}]', xvalue of type 'BADKT<5>', xvalue of type 'int') required here}}
   template<typename KN, typename KT>
   [[clang::sycl_kernel_entry_point(KN)]]
@@ -305,7 +310,8 @@ namespace bad6 {
   // expected-note-re at +2 {{candidate function template not viable: no known conversion from 'const char[{{[0-9]*}}]' to 'int' for 1st argument}}
   template<typename KN, typename... Ts>
   void sycl_kernel_launch(int, Ts...);
-  // expected-error at +4 {{no matching function for call to 'sycl_kernel_launch'}}
+  // expected-error at +5 {{no matching function for call to 'sycl_kernel_launch'}}
+  // expected-note at +3 {{this error is due to a defect in SYCL runtime header files; please report this problem to your SYCL runtime provider}}
   // expected-note-re at +2 {{in implicit call to 'sycl_kernel_launch' with template argument 'BADKN<6>' and function arguments (lvalue of type 'const char[{{[0-9]*}}]', xvalue of type 'BADKT<6>') required here}}
   template<typename KN, typename KT>
   [[clang::sycl_kernel_entry_point(KN)]]
@@ -321,7 +327,8 @@ namespace bad7 {
   // expected-note at +2 {{candidate template ignored: invalid explicitly-specified argument for 1st template parameter}}
   template<int, typename... Ts>
   void sycl_kernel_launch(const char *, Ts...);
-  // expected-error at +3 {{no matching function for call to 'sycl_kernel_launch'}}
+  // expected-error at +4 {{no matching function for call to 'sycl_kernel_launch'}}
+  // expected-note at +2 {{this error is due to a defect in SYCL runtime header files; please report this problem to your SYCL runtime provider}}
   // expected-note-re at +1 {{in implicit call to 'sycl_kernel_launch' with template argument 'BADKN<7>' and function arguments (lvalue of type 'const char[{{[0-9]*}}]', xvalue of type 'BADKT<7>') required here}}
   [[clang::sycl_kernel_entry_point(BADKN<7>)]]
   void skep(BADKT<7> k) {
@@ -334,7 +341,8 @@ namespace bad8 {
   // expected-note at +2 {{candidate template ignored: substitution failure [with KN = BADKN<8>, KT = BADKT<8>]: no type named 'no_such_type' in 'BADKT<8>'}}
   template<typename KN, typename KT, typename T = typename KT::no_such_type>
   void sycl_kernel_launch(const char *, KT);
-  // expected-error at +3 {{no matching function for call to 'sycl_kernel_launch'}}
+  // expected-error at +4 {{no matching function for call to 'sycl_kernel_launch'}}
+  // expected-note at +2 {{this error is due to a defect in SYCL runtime header files; please report this problem to your SYCL runtime provider}}
   // expected-note-re at +1 {{in implicit call to 'sycl_kernel_launch' with template argument 'BADKN<8>' and function arguments (lvalue of type 'const char[{{[0-9]*}}]', xvalue of type 'BADKT<8>') required here}}
   [[clang::sycl_kernel_entry_point(BADKN<8>)]]
   void skep(BADKT<8> k) {
@@ -347,7 +355,8 @@ namespace bad9 {
   // expected-note at +2 {{candidate template ignored: couldn't infer template argument 'T'}}
   template<typename KN, typename KT, typename T>
   void sycl_kernel_launch(const char *, KT);
-  // expected-error at +3 {{no matching function for call to 'sycl_kernel_launch'}}
+  // expected-error at +4 {{no matching function for call to 'sycl_kernel_launch'}}
+  // expected-note at +2 {{this error is due to a defect in SYCL runtime header files; please report this problem to your SYCL runtime provider}}
   // expected-note-re at +1 {{in implicit call to 'sycl_kernel_launch' with template argument 'BADKN<9>' and function arguments (lvalue of type 'const char[{{[0-9]*}}]', xvalue of type 'BADKT<9>') required here}}
   [[clang::sycl_kernel_entry_point(BADKN<9>)]]
   void skep(BADKT<9> k) {
@@ -365,7 +374,8 @@ namespace bad10 {
   };
   template<typename KN>
   launcher<KN> sycl_kernel_launch;
-  // expected-error at +4 {{no matching function for call to object of type 'launcher<BADKN<10, 0>>'}}
+  // expected-error at +5 {{no matching function for call to object of type 'launcher<BADKN<10, 0>>'}}
+  // expected-note at +3 {{this error is due to a defect in SYCL runtime header files; please report this problem to your SYCL runtime provider}}
   // expected-note-re at +2 {{in implicit call to 'sycl_kernel_launch' with template argument 'BADKN<10>' and function arguments (lvalue of type 'const char[{{[0-9]*}}]', xvalue of type 'BADKT<10>') required here}}
   template<typename KN, typename KT>
   [[clang::sycl_kernel_entry_point(KN)]]
@@ -386,7 +396,8 @@ namespace bad11 {
   // expected-note at +1 {{template parameter is declared here}}
   template<int KN>
   launcher<KN> sycl_kernel_launch;
-  // expected-error at +4 {{template argument for non-type template parameter must be an expression}}
+  // expected-error at +5 {{template argument for non-type template parameter must be an expression}}
+  // expected-note at +3 {{this error is due to a defect in SYCL runtime header files; please report this problem to your SYCL runtime provider}}
   // expected-note at +2 {{in implicit call to 'sycl_kernel_launch' with template argument 'KN' required here}}
   template<typename KN, typename KT>
   [[clang::sycl_kernel_entry_point(KN)]]
@@ -407,7 +418,8 @@ namespace bad12 {
   };
   template<typename KN>
   launcher<KN> sycl_kernel_launch;
-  // expected-error at +3 {{'operator()' is a private member of 'bad12::launcher<BADKN<12>>'}}
+  // expected-error at +4 {{'operator()' is a private member of 'bad12::launcher<BADKN<12>>'}}
+  // expected-note at +2 {{this error is due to a defect in SYCL runtime header files; please report this problem to your SYCL runtime provider}}
   // expected-note-re at +1 {{in implicit call to 'sycl_kernel_launch' with template argument 'BADKN<12>' and function arguments (lvalue of type 'const char[{{[0-9]*}}]', xvalue of type 'BADKT<12>') required here}}
   [[clang::sycl_kernel_entry_point(BADKN<12>)]]
   void skep(BADKT<12> k) {
@@ -432,7 +444,8 @@ namespace bad13 {
     template<typename KN>
     launcher<KN> sycl_kernel_launch;
   }
-  // expected-error at +4 {{reference to 'sycl_kernel_launch' is ambiguous}}
+  // expected-error at +5 {{reference to 'sycl_kernel_launch' is ambiguous}}
+  // expected-note at +3 {{this error is due to a defect in SYCL runtime header files; please report this problem to your SYCL runtime provider}}
   // expected-note at +2 {{in implicit call to 'sycl_kernel_launch' with template argument 'KN' required here}}
   template<typename KN, typename KT>
   [[clang::sycl_kernel_entry_point(KN)]]
@@ -450,7 +463,8 @@ namespace bad14 {
   // expected-note at +2 {{candidate function [with KN = BADKN<14>, KT = BADKT<14>]}}
   template<typename KN, typename KT>
   void sycl_kernel_launch(const char *, KT, unsigned char);
-  // expected-error at +3 {{call to 'sycl_kernel_launch' is ambiguous}}
+  // expected-error at +4 {{call to 'sycl_kernel_launch' is ambiguous}}
+  // expected-note at +2 {{this error is due to a defect in SYCL runtime header files; please report this problem to your SYCL runtime provider}}
   // expected-note-re at +1 {{in implicit call to 'sycl_kernel_launch' with template argument 'BADKN<14>' and function arguments (lvalue of type 'const char[{{[0-9]*}}]', xvalue of type 'BADKT<14>', xvalue of type 'int') required here}}
   [[clang::sycl_kernel_entry_point(BADKN<14>)]]
   void skep(BADKT<14> k, int i) {
@@ -463,7 +477,8 @@ namespace bad15 {
   struct S {
     template<typename KN, typename... Ts>
     void sycl_kernel_launch(const char *, Ts...);
-    // expected-error at +3 {{call to non-static member function without an object argument}}
+    // expected-error at +4 {{call to non-static member function without an object argument}}
+    // expected-note at +2 {{this error is due to a defect in SYCL runtime header files; please report this problem to your SYCL runtime provider}}
     // expected-note at +1 {{in implicit call to 'sycl_kernel_launch' with template argument 'BADKN<15>' required here}}
     [[clang::sycl_kernel_entry_point(BADKN<15>)]]
     static void skep(BADKT<15> k) {
@@ -486,7 +501,8 @@ namespace bad16 {
   struct handler : protected base_handler<handler<N>> {
     // Lookup for sycl_kernel_launch fails because lookup in dependent base
     // classes requires explicit qualification.
-    // expected-error at +3 {{explicit qualification required to use member 'sycl_kernel_launch' from dependent base class}}
+    // expected-error at +4 {{explicit qualification required to use member 'sycl_kernel_launch' from dependent base class}}
+    // expected-note at +2 {{this error is due to a defect in SYCL runtime header files; please report this problem to your SYCL runtime provider}}
     // expected-note-re at +1 {{in implicit call to 'sycl_kernel_launch' with template argument 'BADKN<16>' and function arguments (lvalue of type 'const char[{{[0-9]*}}]', xvalue of type 'BADKT<16>') required here}}
     [[clang::sycl_kernel_entry_point(BADKN<16>)]]
     void skep(BADKT<16> k) {
@@ -506,7 +522,8 @@ namespace bad17 {
     // expected-note at +1 {{'non_copyable' has been explicitly marked deleted here}}
     non_copyable(const non_copyable&) = delete;
   };
-  // expected-error at +3 {{call to deleted constructor of 'bad17::non_copyable'}}
+  // expected-error at +4 {{call to deleted constructor of 'bad17::non_copyable'}}
+  // expected-note at +2 {{this error is due to a defect in SYCL runtime header files; please report this problem to your SYCL runtime provider}}
   // expected-note-re at +1 {{in implicit call to 'sycl_kernel_launch' with template argument 'BADKN<17, 0>' and function arguments (lvalue of type 'const char[{{[0-9]*}}]', xvalue of type 'BADKT<17, 0>', xvalue of type 'non_copyable') required here}}
   [[clang::sycl_kernel_entry_point(BADKN<17,0>)]]
   void skep(BADKT<17,0> k, non_copyable) {
@@ -516,7 +533,8 @@ namespace bad17 {
     // expected-note at +1 {{'non_moveable' has been explicitly marked deleted here}}
     non_moveable(non_moveable&&) = delete;
   };
-  // expected-error at +3 {{call to deleted constructor of 'bad17::non_moveable'}}
+  // expected-error at +4 {{call to deleted constructor of 'bad17::non_moveable'}}
+  // expected-note at +2 {{this error is due to a defect in SYCL runtime header files; please report this problem to your SYCL runtime provider}}
   // expected-note-re at +1 {{in implicit call to 'sycl_kernel_launch' with template argument 'BADKN<17, 1>' and function arguments (lvalue of type 'const char[{{[0-9]*}}]', xvalue of type 'BADKT<17, 1>', xvalue of type 'non_moveable') required here}}
   [[clang::sycl_kernel_entry_point(BADKN<17,1>)]]
   void skep(BADKT<17,1> k, non_moveable) {
@@ -526,7 +544,8 @@ namespace bad17 {
 
 // sycl_kernel_launch declared after use and not found by ADL.
 namespace bad18 {
-  // expected-error at +4 {{call to function 'sycl_kernel_launch' that is neither visible in the template definition nor found by argument-dependent lookup}}
+  // expected-error at +5 {{call to function 'sycl_kernel_launch' that is neither visible in the template definition nor found by argument-dependent lookup}}
+  // expected-note at +3 {{this error is due to a defect in SYCL runtime header files; please report this problem to your SYCL runtime provider}}
   // expected-note-re at +2 {{in implicit call to 'sycl_kernel_launch' with template argument 'BADKN<18>' and function arguments (lvalue of type 'const char[{{[0-9]*}}]', xvalue of type 'BADKT<18>') required here}}
   template<typename KN, typename KT>
   [[clang::sycl_kernel_entry_point(KN)]]

>From 13464c4749b7389710f6b45e9e430754e292ad6a Mon Sep 17 00:00:00 2001
From: Tom Honermann <tom.honermann at intel.com>
Date: Wed, 11 Feb 2026 19:41:39 -0800
Subject: [PATCH 23/29] Added messages to existing assertions.

---
 clang/lib/Sema/SemaSYCL.cpp | 13 ++++++++-----
 1 file changed, 8 insertions(+), 5 deletions(-)

diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp
index 8745eacabb0cf..e3f352490b2d6 100644
--- a/clang/lib/Sema/SemaSYCL.cpp
+++ b/clang/lib/Sema/SemaSYCL.cpp
@@ -30,7 +30,7 @@ SemaSYCL::SemaSYCL(Sema &S) : SemaBase(S) {}
 Sema::SemaDiagnosticBuilder SemaSYCL::DiagIfDeviceCode(SourceLocation Loc,
                                                        unsigned DiagID) {
   assert(getLangOpts().SYCLIsDevice &&
-         "Should only be called during SYCL compilation");
+         "Device diagnostics Should only be issued during device compilation");
   SemaDiagnosticBuilder::Kind DiagKind = SemaDiagnosticBuilder::K_Nop;
   FunctionDecl *FD = SemaRef.getCurFunctionDecl(/*AllowLambda=*/true);
   if (FD) {
@@ -223,7 +223,7 @@ void SemaSYCL::handleKernelEntryPointAttr(Decl *D, const ParsedAttr &AL) {
 
 void SemaSYCL::CheckDeviceUseOfDecl(NamedDecl *D, SourceLocation Loc) {
   assert(getLangOpts().SYCLIsDevice &&
-         "Should only be called during SYCL compilation");
+         "Should only be called during SYCL device compilation");
 
   // Function declarations with the sycl_kernel_entry_point attribute cannot
   // be ODR-used in a potentially evaluated context.
@@ -428,7 +428,8 @@ ExprResult SemaSYCL::BuildSYCLKernelLaunchIdExpr(FunctionDecl *FD,
                                                  QualType KNT) {
   // The current context must be the function definition context to ensure
   // that name lookup is performed within the correct scope.
-  assert(SemaRef.CurContext == FD);
+  assert(SemaRef.CurContext == FD && "The current declaration context does not "
+                                     "match the requested function context");
 
   // An appropriate source location is required to emit diagnostics if
   // lookup fails to produce an overload set. The desired location is the
@@ -502,7 +503,8 @@ bool BuildSYCLKernelLaunchCallArgs(Sema &SemaRef, FunctionDecl *FD,
                                    SourceLocation Loc) {
   // The current context must be the function definition context to ensure
   // that parameter references occur within the correct scope.
-  assert(SemaRef.CurContext == FD);
+  assert(SemaRef.CurContext == FD && "The current declaration context does not "
+                                     "match the requested function context");
 
   // Prepare a string literal that contains the kernel name.
   ASTContext &Ctx = SemaRef.getASTContext();
@@ -673,7 +675,8 @@ StmtResult SemaSYCL::BuildSYCLKernelCallStmt(FunctionDecl *FD,
   // The current context must be the function definition context to ensure
   // that name lookup and parameter and local variable creation are performed
   // within the correct scope.
-  assert(SemaRef.CurContext == FD);
+  assert(SemaRef.CurContext == FD && "The current declaration context does not "
+                                     "match the requested function context");
 
   const auto *SKEPAttr = FD->getAttr<SYCLKernelEntryPointAttr>();
   assert(SKEPAttr && "Missing sycl_kernel_entry_point attribute");

>From 86a0342fe2dcaace2820d612d14f115046871f08 Mon Sep 17 00:00:00 2001
From: Tom Honermann <tom.honermann at intel.com>
Date: Thu, 12 Feb 2026 11:51:43 -0800
Subject: [PATCH 24/29] Use a string reference instead of a copy when
 retrieving a kernel name.

---
 clang/lib/Sema/SemaSYCL.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp
index e3f352490b2d6..1cadb3ae994a7 100644
--- a/clang/lib/Sema/SemaSYCL.cpp
+++ b/clang/lib/Sema/SemaSYCL.cpp
@@ -508,7 +508,7 @@ bool BuildSYCLKernelLaunchCallArgs(Sema &SemaRef, FunctionDecl *FD,
 
   // Prepare a string literal that contains the kernel name.
   ASTContext &Ctx = SemaRef.getASTContext();
-  const std::string KernelName = SKI->GetKernelName();
+  const std::string &KernelName = SKI->GetKernelName();
   QualType KernelNameCharTy = Ctx.CharTy.withConst();
   llvm::APInt KernelNameSize(Ctx.getTypeSize(Ctx.getSizeType()),
                              KernelName.size() + 1);

>From 5df2a93b6d0cc57e6fc59579d02bfa9cea09e4c9 Mon Sep 17 00:00:00 2001
From: Tom Honermann <tom.honermann at intel.com>
Date: Thu, 12 Feb 2026 11:59:41 -0800
Subject: [PATCH 25/29] Address code review feedback from Alexey Bader.

---
 clang/include/clang/AST/StmtSYCL.h              | 6 ------
 clang/include/clang/Basic/AttrDocs.td           | 2 +-
 clang/include/clang/Serialization/ASTBitCodes.h | 2 +-
 clang/lib/Sema/SemaSYCL.cpp                     | 5 +++--
 4 files changed, 5 insertions(+), 10 deletions(-)

diff --git a/clang/include/clang/AST/StmtSYCL.h b/clang/include/clang/AST/StmtSYCL.h
index f3f4f040fb63c..524468fd555db 100644
--- a/clang/include/clang/AST/StmtSYCL.h
+++ b/clang/include/clang/AST/StmtSYCL.h
@@ -51,27 +51,21 @@ class SYCLKernelCallStmt : public Stmt {
   /// Construct an empty SYCL kernel call statement.
   SYCLKernelCallStmt(EmptyShell Empty) : Stmt(SYCLKernelCallStmtClass, Empty) {}
 
-  /// Retrieve the original statement.
   CompoundStmt *getOriginalStmt() { return cast<CompoundStmt>(OriginalStmt); }
   const CompoundStmt *getOriginalStmt() const {
     return cast<CompoundStmt>(OriginalStmt);
   }
 
-  /// Set the original statement.
   void setOriginalStmt(CompoundStmt *CS) { OriginalStmt = CS; }
 
-  /// Retrieve the kernel launch statement.
   Stmt *getKernelLaunchStmt() { return KernelLaunchStmt; }
   const Stmt *getKernelLaunchStmt() const { return KernelLaunchStmt; }
 
-  /// Set the kernel launch statement.
   void setKernelLaunchStmt(Stmt *S) { KernelLaunchStmt = S; }
 
-  /// Retrieve the outlined function declaration.
   OutlinedFunctionDecl *getOutlinedFunctionDecl() { return OFDecl; }
   const OutlinedFunctionDecl *getOutlinedFunctionDecl() const { return OFDecl; }
 
-  /// Set the outlined function declaration.
   void setOutlinedFunctionDecl(OutlinedFunctionDecl *OFD) { OFDecl = OFD; }
 
   SourceLocation getBeginLoc() const LLVM_READONLY {
diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td
index 907b8029be3e1..8aadc6d8086db 100644
--- a/clang/include/clang/Basic/AttrDocs.td
+++ b/clang/include/clang/Basic/AttrDocs.td
@@ -708,7 +708,7 @@ There are a few items worthy of note:
 
 #. The ``sycl_kernel_launch`` template is expected to be provided by the SYCL
    library implementation. It is responsible for copying the kernel arguments
-   to device memory  and for scheduling execution of the generated offload
+   to device memory and for scheduling execution of the generated offload
    kernel entry point identified by the symbol name passed as the first
    function argument. ``sycl-kernel-caller-for-KN`` is substituted above for
    the actual symbol name that would be generated for the offload kernel entry
diff --git a/clang/include/clang/Serialization/ASTBitCodes.h b/clang/include/clang/Serialization/ASTBitCodes.h
index 08f6f21c7246f..752e7fd288aa6 100644
--- a/clang/include/clang/Serialization/ASTBitCodes.h
+++ b/clang/include/clang/Serialization/ASTBitCodes.h
@@ -1618,7 +1618,7 @@ enum StmtCode {
   /// A SYCLKernelCallStmt record.
   STMT_SYCLKERNELCALL,
 
-  /// A SYCLKernelCallStmt record.
+  /// An UnresolvedSYCLKernelCallStmt record.
   STMT_UNRESOLVED_SYCL_KERNEL_CALL,
 
   /// A GCC-style AsmStmt record.
diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp
index 1cadb3ae994a7..c65f29ad415a4 100644
--- a/clang/lib/Sema/SemaSYCL.cpp
+++ b/clang/lib/Sema/SemaSYCL.cpp
@@ -472,14 +472,15 @@ ExprResult SemaSYCL::BuildSYCLKernelLaunchIdExpr(FunctionDecl *FD,
 
   ExprResult IdExpr;
   if (SemaRef.isPotentialImplicitMemberAccess(EmptySS, Result,
-                                              /*IsAddressOfOperand*/ false))
+                                              /*IsAddressOfOperand*/ false)) {
     // The lookup result allows for a possible implicit member access that
     // would require an implicit or explicit 'this' argument.
     IdExpr = SemaRef.BuildPossibleImplicitMemberExpr(
         EmptySS, SourceLocation(), Result, &TALI, SemaRef.getCurScope());
-  else
+  } else {
     IdExpr = SemaRef.BuildTemplateIdExpr(EmptySS, SourceLocation(), Result,
                                          /*RequiresADL*/ true, &TALI);
+  }
 
   // The resulting expression may be invalid if, for example, 'FD' is a
   // non-static member function and sycl_kernel_launch lookup selects a

>From 2a7254c4c8327c8ddae46dc016b5498aa8228f17 Mon Sep 17 00:00:00 2001
From: Tom Honermann <tom.honermann at intel.com>
Date: Thu, 12 Feb 2026 12:41:30 -0800
Subject: [PATCH 26/29] Fix test failures due to dead_on_return additions.

---
 clang/test/CodeGenSYCL/kernel-caller-entry-point.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/clang/test/CodeGenSYCL/kernel-caller-entry-point.cpp b/clang/test/CodeGenSYCL/kernel-caller-entry-point.cpp
index 596b5316e6330..47c2c45ae7749 100644
--- a/clang/test/CodeGenSYCL/kernel-caller-entry-point.cpp
+++ b/clang/test/CodeGenSYCL/kernel-caller-entry-point.cpp
@@ -148,7 +148,7 @@ int main() {
 // CHECK-HOST-LINUX-NEXT:   %0 = load i32, ptr %a.addr, align 4
 // CHECK-HOST-LINUX-NEXT:   %1 = load i32, ptr %b.addr, align 4
 // CHECK-HOST-LINUX-NEXT:   call void @_ZN7handler18sycl_kernel_launchIZ4mainE2KNJZ4mainEUliiE_iiEEEvPKcDpT0_(ptr noundef nonnull align 1 dereferenceable(1) %this1, ptr noundef @.str.3, ptr noundef %agg.tmp, i32 noundef %0, i32 noundef %1)
-// CHECK-HOST-LINUX-NEXT:   call void @_ZZ4mainENUliiE_D1Ev(ptr noundef nonnull align 4 dereferenceable(4) %agg.tmp) #{{[0-9]+}}
+// CHECK-HOST-LINUX-NEXT:   call void @_ZZ4mainENUliiE_D1Ev(ptr noundef nonnull align 4 dead_on_return(4) dereferenceable(4) %agg.tmp) #{{[0-9]+}}
 // CHECK-HOST-LINUX-NEXT:   ret void
 // CHECK-HOST-LINUX-NEXT: }
 
@@ -211,7 +211,7 @@ int main() {
 // CHECK-HOST-WINDOWS-NEXT:   %coerce.dive4 = getelementptr inbounds nuw %struct.copyable, ptr %coerce.dive3, i32 0, i32 0
 // CHECK-HOST-WINDOWS-NEXT:   %2 = load i32, ptr %coerce.dive4, align 4
 // CHECK-HOST-WINDOWS-NEXT:   call void @"??$sycl_kernel_launch at UKN@?1??main@@9 at V<lambda_3>@?0??2 at 9@HH at handler@@AEAAXPEBDV<lambda_3>@?0??main@@9 at HH@Z"(ptr noundef nonnull align 1 dereferenceable(1) %this2, ptr noundef @"??_C at _0P@DLGHPODL at _ZTSZ4mainE2KN?$AA@", i32 %2, i32 noundef %1, i32 noundef %0)
-// CHECK-HOST-WINDOWS-NEXT:   call void @"??1<lambda_3>@?0??main@@9 at QEAA@XZ"(ptr noundef nonnull align 4 dereferenceable(4) %k) #{{[0-9]+}}
+// CHECK-HOST-WINDOWS-NEXT:   call void @"??1<lambda_3>@?0??main@@9 at QEAA@XZ"(ptr noundef nonnull align 4 dead_on_return(4) dereferenceable(4) %k) #{{[0-9]+}}
 // CHECK-HOST-WINDOWS-NEXT:   ret void
 // CHECK-HOST-WINDOWS-NEXT: }
 

>From 61075b2a0d562ae363fb0cd1486adc2212b3fec3 Mon Sep 17 00:00:00 2001
From: Tom Honermann <tom.honermann at intel.com>
Date: Tue, 3 Mar 2026 13:37:03 -0800
Subject: [PATCH 27/29] Address Erich's concerns regarding device dependent
 behavior following an assertion failure.

---
 clang/lib/CodeGen/CodeGenSYCL.cpp | 21 ++++++++-------------
 1 file changed, 8 insertions(+), 13 deletions(-)

diff --git a/clang/lib/CodeGen/CodeGenSYCL.cpp b/clang/lib/CodeGen/CodeGenSYCL.cpp
index 74c1a68f1526d..abd690030dbee 100644
--- a/clang/lib/CodeGen/CodeGenSYCL.cpp
+++ b/clang/lib/CodeGen/CodeGenSYCL.cpp
@@ -18,19 +18,14 @@ using namespace clang;
 using namespace CodeGen;
 
 void CodeGenFunction::EmitSYCLKernelCallStmt(const SYCLKernelCallStmt &S) {
-  if (getLangOpts().SYCLIsDevice) {
-    // A definition for a sycl_kernel_entry_point attributed function should
-    // never be emitted during device compilation; a diagnostic should be
-    // issued for any such ODR-use.
-    assert(false && "Attempt to emit a sycl_kernel_entry_point function during "
-                    "device compilation");
-    // However, if a definition is somehow emitted, emit an unreachable
-    // instruction to thwart any attempted execution.
-    EmitUnreachable(S.getBeginLoc());
-  } else {
-    assert(getLangOpts().SYCLIsHost);
-    EmitStmt(S.getKernelLaunchStmt());
-  }
+  // SYCLKernelCallStmt instances are only injected in the definitions of
+  // functions declared with the sycl_kernel_entry_point attribute. ODR-use of
+  // such a function in code emitted during device compilation should be
+  // diagnosed. Thus, any attempt to emit a SYCLKernelCallStmt during device
+  // compilation indicates a missing diagnostic.
+  assert(!getLangOpts().SYCLIsDevice, "Attempt to emit a SYCL kernel call "
+                                      "statement during device compilation");
+  EmitStmt(S.getKernelLaunchStmt());
 }
 
 static void SetSYCLKernelAttributes(llvm::Function *Fn, CodeGenFunction &CGF) {

>From e7ec0d6fd7ad959f4539af4191f5b8b98ef67cf5 Mon Sep 17 00:00:00 2001
From: Tom Honermann <tom.honermann at intel.com>
Date: Wed, 4 Mar 2026 15:07:23 -0800
Subject: [PATCH 28/29] Correct invalid assert syntax.

Next time I'll remember to compile my changes before pushing to a PR.
---
 clang/lib/CodeGen/CodeGenSYCL.cpp | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/clang/lib/CodeGen/CodeGenSYCL.cpp b/clang/lib/CodeGen/CodeGenSYCL.cpp
index abd690030dbee..5a52675de299d 100644
--- a/clang/lib/CodeGen/CodeGenSYCL.cpp
+++ b/clang/lib/CodeGen/CodeGenSYCL.cpp
@@ -13,6 +13,7 @@
 
 #include "CodeGenFunction.h"
 #include "CodeGenModule.h"
+#include <cassert>
 
 using namespace clang;
 using namespace CodeGen;
@@ -23,8 +24,9 @@ void CodeGenFunction::EmitSYCLKernelCallStmt(const SYCLKernelCallStmt &S) {
   // such a function in code emitted during device compilation should be
   // diagnosed. Thus, any attempt to emit a SYCLKernelCallStmt during device
   // compilation indicates a missing diagnostic.
-  assert(!getLangOpts().SYCLIsDevice, "Attempt to emit a SYCL kernel call "
-                                      "statement during device compilation");
+  assert(!getLangOpts().SYCLIsDevice &&
+         "Attempt to emit a SYCL kernel call statement during device"
+         " compilation");
   EmitStmt(S.getKernelLaunchStmt());
 }
 

>From 45450c895daf6fa838bd9951d4ac8552950a2396 Mon Sep 17 00:00:00 2001
From: Tom Honermann <tom.honermann at intel.com>
Date: Wed, 4 Mar 2026 15:08:40 -0800
Subject: [PATCH 29/29] Adjust the diagnostic note issued when a viable
 sycl_kernel_launch declaration isn't found.

---
 .../clang/Basic/DiagnosticSemaKinds.td        |  4 +-
 .../SemaSYCL/sycl-kernel-launch-ms-compat.cpp |  4 +-
 clang/test/SemaSYCL/sycl-kernel-launch.cpp    | 38 +++++++++----------
 3 files changed, 23 insertions(+), 23 deletions(-)

diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 65e2018980382..7439f00c74498 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -13285,8 +13285,8 @@ def err_sycl_entry_point_deduced_return_type : Error<
   "the %0 attribute only applies to functions with a non-deduced 'void' return"
   " type">;
 def note_sycl_runtime_defect : Note<
-  "this error is due to a defect in SYCL runtime header files; please report"
-  " this problem to your SYCL runtime provider">;
+  "this indicates a problem with the SYCL runtime header files; please consider"
+  " reporting this to your SYCL runtime provider">;
 def note_sycl_kernel_launch_lookup_here : Note<
   "in implicit call to 'sycl_kernel_launch' with template argument %0 required"
   " here">;
diff --git a/clang/test/SemaSYCL/sycl-kernel-launch-ms-compat.cpp b/clang/test/SemaSYCL/sycl-kernel-launch-ms-compat.cpp
index 12eed1bbe29ec..cd186a833b024 100644
--- a/clang/test/SemaSYCL/sycl-kernel-launch-ms-compat.cpp
+++ b/clang/test/SemaSYCL/sycl-kernel-launch-ms-compat.cpp
@@ -33,7 +33,7 @@ namespace ok1 {
     // sycl_kernel_launch would not consider dependent base classes. Such
     // lookups are allowed as a Microsoft compatible extension.
     // expected-warning at +4 {{use of member 'sycl_kernel_launch' found via unqualified lookup into dependent bases of class templates is a Microsoft extension}}
-    // expected-note at +2 {{this error is due to a defect in SYCL runtime header files; please report this problem to your SYCL runtime provider}}
+    // expected-note at +2 {{this indicates a problem with the SYCL runtime header files; please consider reporting this to your SYCL runtime provider}}
     // expected-note-re at +1 {{in implicit call to 'sycl_kernel_launch' with template argument 'KN<1>' and function arguments (lvalue of type 'const char[{{[0-9]*}}]', xvalue of type 'KT<1>') required here}}
     [[clang::sycl_kernel_entry_point(KN<1>)]]
     void skep(KT<1> k) {
@@ -75,7 +75,7 @@ namespace bad1 {
     // compatible extension, but access checks are still performed which makes
     // this case an error.
     // expected-warning at +5 {{use of member 'sycl_kernel_launch' found via unqualified lookup into dependent bases of class templates is a Microsoft extension}}
-    // expected-note at +3 {{this error is due to a defect in SYCL runtime header files; please report this problem to your SYCL runtime provider}}
+    // expected-note at +3 {{this indicates a problem with the SYCL runtime header files; please consider reporting this to your SYCL runtime provider}}
     // expected-note-re at +2 {{in implicit call to 'sycl_kernel_launch' with template argument 'BADKN<1>' and function arguments (lvalue of type 'const char[{{[0-9]*}}]', xvalue of type 'BADKT<1>') required here}}
     // expected-error at +2 {{'sycl_kernel_launch' is a private member of 'bad1::base_handler<bad1::handler<1>>'}}
     [[clang::sycl_kernel_entry_point(BADKN<1>)]]
diff --git a/clang/test/SemaSYCL/sycl-kernel-launch.cpp b/clang/test/SemaSYCL/sycl-kernel-launch.cpp
index dfd55a2424248..20d9becb81929 100644
--- a/clang/test/SemaSYCL/sycl-kernel-launch.cpp
+++ b/clang/test/SemaSYCL/sycl-kernel-launch.cpp
@@ -238,7 +238,7 @@ struct BADKT {
 // Undeclared sycl_kernel_launch identifier from non-template function.
 namespace bad1 {
   // expected-error at +4 {{use of undeclared identifier 'sycl_kernel_launch'}}
-  // expected-note at +2 {{this error is due to a defect in SYCL runtime header files; please report this problem to your SYCL runtime provider}}
+  // expected-note at +2 {{this indicates a problem with the SYCL runtime header files; please consider reporting this to your SYCL runtime provider}}
   // expected-note-re at +1 {{in implicit call to 'sycl_kernel_launch' with template argument 'BADKN<1>' and function arguments (lvalue of type 'const char[{{[0-9]*}}]', xvalue of type 'BADKT<1>') required here}}
   [[clang::sycl_kernel_entry_point(BADKN<1>)]]
   void skep(BADKT<1> k) {
@@ -249,7 +249,7 @@ namespace bad1 {
 // Undeclared sycl_kernel_launch identifier from function template.
 namespace bad2 {
   // expected-error at +5 {{use of undeclared identifier 'sycl_kernel_launch'}}
-  // expected-note at +3 {{this error is due to a defect in SYCL runtime header files; please report this problem to your SYCL runtime provider}}
+  // expected-note at +3 {{this indicates a problem with the SYCL runtime header files; please consider reporting this to your SYCL runtime provider}}
   // expected-note-re at +2 {{in implicit call to 'sycl_kernel_launch' with template argument 'BADKN<2>' and function arguments (lvalue of type 'const char[{{[0-9]*}}]', xvalue of type 'BADKT<2>') required here}}
   template<typename KN, typename KT>
   [[clang::sycl_kernel_entry_point(KN)]]
@@ -265,7 +265,7 @@ namespace bad3 {
   // expected-note at +1 {{declared as a non-template here}}
   void sycl_kernel_launch(const char *, BADKT<3>);
   // expected-error at +4 {{'sycl_kernel_launch' does not refer to a template}}
-  // expected-note at +2 {{this error is due to a defect in SYCL runtime header files; please report this problem to your SYCL runtime provider}}
+  // expected-note at +2 {{this indicates a problem with the SYCL runtime header files; please consider reporting this to your SYCL runtime provider}}
   // expected-note at +1 {{in implicit call to 'sycl_kernel_launch' with template argument 'BADKN<3>' required here}}
   [[clang::sycl_kernel_entry_point(BADKN<3>)]]
   void skep(BADKT<3> k) {
@@ -279,7 +279,7 @@ namespace bad4 {
   template<typename KN, typename KT>
   void sycl_kernel_launch(const char *, KT);
   // expected-error at +5 {{no matching function for call to 'sycl_kernel_launch'}}
-  // expected-note at +3 {{this error is due to a defect in SYCL runtime header files; please report this problem to your SYCL runtime provider}}
+  // expected-note at +3 {{this indicates a problem with the SYCL runtime header files; please consider reporting this to your SYCL runtime provider}}
   // expected-note-re at +2 {{in implicit call to 'sycl_kernel_launch' with template argument 'BADKN<4>' and function arguments (lvalue of type 'const char[{{[0-9]*}}]') required here}}
   template<typename KN>
   [[clang::sycl_kernel_entry_point(KN)]]
@@ -294,7 +294,7 @@ namespace bad5 {
   template<typename KN, typename KT>
   void sycl_kernel_launch(const char *, KT);
   // expected-error at +5 {{no matching function for call to 'sycl_kernel_launch'}}
-  // expected-note at +3 {{this error is due to a defect in SYCL runtime header files; please report this problem to your SYCL runtime provider}}
+  // expected-note at +3 {{this indicates a problem with the SYCL runtime header files; please consider reporting this to your SYCL runtime provider}}
   // expected-note-re at +2 {{in implicit call to 'sycl_kernel_launch' with template argument 'BADKN<5>' and function arguments (lvalue of type 'const char[{{[0-9]*}}]', xvalue of type 'BADKT<5>', xvalue of type 'int') required here}}
   template<typename KN, typename KT>
   [[clang::sycl_kernel_entry_point(KN)]]
@@ -311,7 +311,7 @@ namespace bad6 {
   template<typename KN, typename... Ts>
   void sycl_kernel_launch(int, Ts...);
   // expected-error at +5 {{no matching function for call to 'sycl_kernel_launch'}}
-  // expected-note at +3 {{this error is due to a defect in SYCL runtime header files; please report this problem to your SYCL runtime provider}}
+  // expected-note at +3 {{this indicates a problem with the SYCL runtime header files; please consider reporting this to your SYCL runtime provider}}
   // expected-note-re at +2 {{in implicit call to 'sycl_kernel_launch' with template argument 'BADKN<6>' and function arguments (lvalue of type 'const char[{{[0-9]*}}]', xvalue of type 'BADKT<6>') required here}}
   template<typename KN, typename KT>
   [[clang::sycl_kernel_entry_point(KN)]]
@@ -328,7 +328,7 @@ namespace bad7 {
   template<int, typename... Ts>
   void sycl_kernel_launch(const char *, Ts...);
   // expected-error at +4 {{no matching function for call to 'sycl_kernel_launch'}}
-  // expected-note at +2 {{this error is due to a defect in SYCL runtime header files; please report this problem to your SYCL runtime provider}}
+  // expected-note at +2 {{this indicates a problem with the SYCL runtime header files; please consider reporting this to your SYCL runtime provider}}
   // expected-note-re at +1 {{in implicit call to 'sycl_kernel_launch' with template argument 'BADKN<7>' and function arguments (lvalue of type 'const char[{{[0-9]*}}]', xvalue of type 'BADKT<7>') required here}}
   [[clang::sycl_kernel_entry_point(BADKN<7>)]]
   void skep(BADKT<7> k) {
@@ -342,7 +342,7 @@ namespace bad8 {
   template<typename KN, typename KT, typename T = typename KT::no_such_type>
   void sycl_kernel_launch(const char *, KT);
   // expected-error at +4 {{no matching function for call to 'sycl_kernel_launch'}}
-  // expected-note at +2 {{this error is due to a defect in SYCL runtime header files; please report this problem to your SYCL runtime provider}}
+  // expected-note at +2 {{this indicates a problem with the SYCL runtime header files; please consider reporting this to your SYCL runtime provider}}
   // expected-note-re at +1 {{in implicit call to 'sycl_kernel_launch' with template argument 'BADKN<8>' and function arguments (lvalue of type 'const char[{{[0-9]*}}]', xvalue of type 'BADKT<8>') required here}}
   [[clang::sycl_kernel_entry_point(BADKN<8>)]]
   void skep(BADKT<8> k) {
@@ -356,7 +356,7 @@ namespace bad9 {
   template<typename KN, typename KT, typename T>
   void sycl_kernel_launch(const char *, KT);
   // expected-error at +4 {{no matching function for call to 'sycl_kernel_launch'}}
-  // expected-note at +2 {{this error is due to a defect in SYCL runtime header files; please report this problem to your SYCL runtime provider}}
+  // expected-note at +2 {{this indicates a problem with the SYCL runtime header files; please consider reporting this to your SYCL runtime provider}}
   // expected-note-re at +1 {{in implicit call to 'sycl_kernel_launch' with template argument 'BADKN<9>' and function arguments (lvalue of type 'const char[{{[0-9]*}}]', xvalue of type 'BADKT<9>') required here}}
   [[clang::sycl_kernel_entry_point(BADKN<9>)]]
   void skep(BADKT<9> k) {
@@ -375,7 +375,7 @@ namespace bad10 {
   template<typename KN>
   launcher<KN> sycl_kernel_launch;
   // expected-error at +5 {{no matching function for call to object of type 'launcher<BADKN<10, 0>>'}}
-  // expected-note at +3 {{this error is due to a defect in SYCL runtime header files; please report this problem to your SYCL runtime provider}}
+  // expected-note at +3 {{this indicates a problem with the SYCL runtime header files; please consider reporting this to your SYCL runtime provider}}
   // expected-note-re at +2 {{in implicit call to 'sycl_kernel_launch' with template argument 'BADKN<10>' and function arguments (lvalue of type 'const char[{{[0-9]*}}]', xvalue of type 'BADKT<10>') required here}}
   template<typename KN, typename KT>
   [[clang::sycl_kernel_entry_point(KN)]]
@@ -397,7 +397,7 @@ namespace bad11 {
   template<int KN>
   launcher<KN> sycl_kernel_launch;
   // expected-error at +5 {{template argument for non-type template parameter must be an expression}}
-  // expected-note at +3 {{this error is due to a defect in SYCL runtime header files; please report this problem to your SYCL runtime provider}}
+  // expected-note at +3 {{this indicates a problem with the SYCL runtime header files; please consider reporting this to your SYCL runtime provider}}
   // expected-note at +2 {{in implicit call to 'sycl_kernel_launch' with template argument 'KN' required here}}
   template<typename KN, typename KT>
   [[clang::sycl_kernel_entry_point(KN)]]
@@ -419,7 +419,7 @@ namespace bad12 {
   template<typename KN>
   launcher<KN> sycl_kernel_launch;
   // expected-error at +4 {{'operator()' is a private member of 'bad12::launcher<BADKN<12>>'}}
-  // expected-note at +2 {{this error is due to a defect in SYCL runtime header files; please report this problem to your SYCL runtime provider}}
+  // expected-note at +2 {{this indicates a problem with the SYCL runtime header files; please consider reporting this to your SYCL runtime provider}}
   // expected-note-re at +1 {{in implicit call to 'sycl_kernel_launch' with template argument 'BADKN<12>' and function arguments (lvalue of type 'const char[{{[0-9]*}}]', xvalue of type 'BADKT<12>') required here}}
   [[clang::sycl_kernel_entry_point(BADKN<12>)]]
   void skep(BADKT<12> k) {
@@ -445,7 +445,7 @@ namespace bad13 {
     launcher<KN> sycl_kernel_launch;
   }
   // expected-error at +5 {{reference to 'sycl_kernel_launch' is ambiguous}}
-  // expected-note at +3 {{this error is due to a defect in SYCL runtime header files; please report this problem to your SYCL runtime provider}}
+  // expected-note at +3 {{this indicates a problem with the SYCL runtime header files; please consider reporting this to your SYCL runtime provider}}
   // expected-note at +2 {{in implicit call to 'sycl_kernel_launch' with template argument 'KN' required here}}
   template<typename KN, typename KT>
   [[clang::sycl_kernel_entry_point(KN)]]
@@ -464,7 +464,7 @@ namespace bad14 {
   template<typename KN, typename KT>
   void sycl_kernel_launch(const char *, KT, unsigned char);
   // expected-error at +4 {{call to 'sycl_kernel_launch' is ambiguous}}
-  // expected-note at +2 {{this error is due to a defect in SYCL runtime header files; please report this problem to your SYCL runtime provider}}
+  // expected-note at +2 {{this indicates a problem with the SYCL runtime header files; please consider reporting this to your SYCL runtime provider}}
   // expected-note-re at +1 {{in implicit call to 'sycl_kernel_launch' with template argument 'BADKN<14>' and function arguments (lvalue of type 'const char[{{[0-9]*}}]', xvalue of type 'BADKT<14>', xvalue of type 'int') required here}}
   [[clang::sycl_kernel_entry_point(BADKN<14>)]]
   void skep(BADKT<14> k, int i) {
@@ -478,7 +478,7 @@ namespace bad15 {
     template<typename KN, typename... Ts>
     void sycl_kernel_launch(const char *, Ts...);
     // expected-error at +4 {{call to non-static member function without an object argument}}
-    // expected-note at +2 {{this error is due to a defect in SYCL runtime header files; please report this problem to your SYCL runtime provider}}
+    // expected-note at +2 {{this indicates a problem with the SYCL runtime header files; please consider reporting this to your SYCL runtime provider}}
     // expected-note at +1 {{in implicit call to 'sycl_kernel_launch' with template argument 'BADKN<15>' required here}}
     [[clang::sycl_kernel_entry_point(BADKN<15>)]]
     static void skep(BADKT<15> k) {
@@ -502,7 +502,7 @@ namespace bad16 {
     // Lookup for sycl_kernel_launch fails because lookup in dependent base
     // classes requires explicit qualification.
     // expected-error at +4 {{explicit qualification required to use member 'sycl_kernel_launch' from dependent base class}}
-    // expected-note at +2 {{this error is due to a defect in SYCL runtime header files; please report this problem to your SYCL runtime provider}}
+    // expected-note at +2 {{this indicates a problem with the SYCL runtime header files; please consider reporting this to your SYCL runtime provider}}
     // expected-note-re at +1 {{in implicit call to 'sycl_kernel_launch' with template argument 'BADKN<16>' and function arguments (lvalue of type 'const char[{{[0-9]*}}]', xvalue of type 'BADKT<16>') required here}}
     [[clang::sycl_kernel_entry_point(BADKN<16>)]]
     void skep(BADKT<16> k) {
@@ -523,7 +523,7 @@ namespace bad17 {
     non_copyable(const non_copyable&) = delete;
   };
   // expected-error at +4 {{call to deleted constructor of 'bad17::non_copyable'}}
-  // expected-note at +2 {{this error is due to a defect in SYCL runtime header files; please report this problem to your SYCL runtime provider}}
+  // expected-note at +2 {{this indicates a problem with the SYCL runtime header files; please consider reporting this to your SYCL runtime provider}}
   // expected-note-re at +1 {{in implicit call to 'sycl_kernel_launch' with template argument 'BADKN<17, 0>' and function arguments (lvalue of type 'const char[{{[0-9]*}}]', xvalue of type 'BADKT<17, 0>', xvalue of type 'non_copyable') required here}}
   [[clang::sycl_kernel_entry_point(BADKN<17,0>)]]
   void skep(BADKT<17,0> k, non_copyable) {
@@ -534,7 +534,7 @@ namespace bad17 {
     non_moveable(non_moveable&&) = delete;
   };
   // expected-error at +4 {{call to deleted constructor of 'bad17::non_moveable'}}
-  // expected-note at +2 {{this error is due to a defect in SYCL runtime header files; please report this problem to your SYCL runtime provider}}
+  // expected-note at +2 {{this indicates a problem with the SYCL runtime header files; please consider reporting this to your SYCL runtime provider}}
   // expected-note-re at +1 {{in implicit call to 'sycl_kernel_launch' with template argument 'BADKN<17, 1>' and function arguments (lvalue of type 'const char[{{[0-9]*}}]', xvalue of type 'BADKT<17, 1>', xvalue of type 'non_moveable') required here}}
   [[clang::sycl_kernel_entry_point(BADKN<17,1>)]]
   void skep(BADKT<17,1> k, non_moveable) {
@@ -545,7 +545,7 @@ namespace bad17 {
 // sycl_kernel_launch declared after use and not found by ADL.
 namespace bad18 {
   // expected-error at +5 {{call to function 'sycl_kernel_launch' that is neither visible in the template definition nor found by argument-dependent lookup}}
-  // expected-note at +3 {{this error is due to a defect in SYCL runtime header files; please report this problem to your SYCL runtime provider}}
+  // expected-note at +3 {{this indicates a problem with the SYCL runtime header files; please consider reporting this to your SYCL runtime provider}}
   // expected-note-re at +2 {{in implicit call to 'sycl_kernel_launch' with template argument 'BADKN<18>' and function arguments (lvalue of type 'const char[{{[0-9]*}}]', xvalue of type 'BADKT<18>') required here}}
   template<typename KN, typename KT>
   [[clang::sycl_kernel_entry_point(KN)]]



More information about the cfe-commits mailing list