https://github.com/Fznamznon created 
https://github.com/llvm/llvm-project/pull/196128

WIP

>From e512f79b89aaf2dcf4b168324d55b924aa24e54b Mon Sep 17 00:00:00 2001
From: "Podchishchaeva, Mariya" <[email protected]>
Date: Tue, 24 Feb 2026 14:03:17 -0800
Subject: [PATCH] [clang][SYCL] Decomposition support

WIP
---
 clang/include/clang/AST/ASTNodeTraverser.h    |   4 +-
 clang/include/clang/AST/RecursiveASTVisitor.h |   1 +
 clang/include/clang/AST/StmtSYCL.h            |  26 +-
 clang/include/clang/Basic/Attr.td             |   7 +
 clang/include/clang/Sema/ScopeInfo.h          |   4 +
 clang/include/clang/Sema/SemaSYCL.h           |   9 +-
 clang/lib/Sema/SemaDecl.cpp                   |  18 +-
 clang/lib/Sema/SemaDeclAttr.cpp               |   3 +
 clang/lib/Sema/SemaSYCL.cpp                   | 485 ++++++++++++++++--
 clang/lib/Sema/TreeTransform.h                |   7 +-
 .../ast-dump-sycl-kernel-call-stmt.cpp        |   3 +
 .../ast-dump-sycl-kernel-decomposition.cpp    | 141 +++++
 .../ast-dump-sycl-kernel-entry-point.cpp      |   3 +
 .../ASTSYCL/ast-print-sycl-kernel-call.cpp    |   3 +
 clang/test/CodeGenSYCL/function-attrs.cpp     |   3 +
 .../CodeGenSYCL/kernel-arg-decomposition.cpp  |  96 ++++
 .../CodeGenSYCL/kernel-caller-entry-point.cpp |   3 +
 .../sycl-kernel-entry-point-exceptions.cpp    |   3 +
 .../unique_stable_name_windows_diff.cpp       |   3 +
 ...-kernel-entry-point-attr-appertainment.cpp |   3 +
 ...kernel-entry-point-attr-device-odr-use.cpp |   3 +
 .../sycl-kernel-entry-point-attr-grammar.cpp  |   3 +
 ...el-entry-point-attr-kernel-name-module.cpp |   3 +
 ...ernel-entry-point-attr-kernel-name-pch.cpp |   3 +
 ...cl-kernel-entry-point-attr-kernel-name.cpp |   3 +
 .../sycl-kernel-entry-point-attr-sfinae.cpp   |   3 +
 .../sycl-kernel-entry-point-attr-this.cpp     |   3 +
 .../SemaSYCL/sycl-kernel-launch-ms-compat.cpp |   3 +
 clang/test/SemaSYCL/sycl-kernel-launch.cpp    |   3 +
 29 files changed, 802 insertions(+), 50 deletions(-)
 create mode 100644 clang/test/ASTSYCL/ast-dump-sycl-kernel-decomposition.cpp
 create mode 100644 clang/test/CodeGenSYCL/kernel-arg-decomposition.cpp

diff --git a/clang/include/clang/AST/ASTNodeTraverser.h 
b/clang/include/clang/AST/ASTNodeTraverser.h
index 5e9463d54747d..c4bafc2017609 100644
--- a/clang/include/clang/AST/ASTNodeTraverser.h
+++ b/clang/include/clang/AST/ASTNodeTraverser.h
@@ -858,8 +858,10 @@ class ASTNodeTraverser
   void
   VisitUnresolvedSYCLKernelCallStmt(const UnresolvedSYCLKernelCallStmt *Node) {
     Visit(Node->getOriginalStmt());
-    if (Traversal != TK_IgnoreUnlessSpelledInSource)
+    if (Traversal != TK_IgnoreUnlessSpelledInSource) {
       Visit(Node->getKernelLaunchIdExpr());
+      Visit(Node->getSpecArgsIdExpr());
+    }
   }
 
   void VisitOMPExecutableDirective(const OMPExecutableDirective *Node) {
diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h 
b/clang/include/clang/AST/RecursiveASTVisitor.h
index b5be0910194bd..fdb828a7cb680 100644
--- a/clang/include/clang/AST/RecursiveASTVisitor.h
+++ b/clang/include/clang/AST/RecursiveASTVisitor.h
@@ -3034,6 +3034,7 @@ DEF_TRAVERSE_STMT(UnresolvedSYCLKernelCallStmt, {
   if (getDerived().shouldVisitImplicitCode()) {
     TRY_TO(TraverseStmt(S->getOriginalStmt()));
     TRY_TO(TraverseStmt(S->getKernelLaunchIdExpr()));
+    TRY_TO(TraverseStmt(S->getSpecArgsIdExpr()));
     ShouldVisitChildren = false;
   }
 })
diff --git a/clang/include/clang/AST/StmtSYCL.h 
b/clang/include/clang/AST/StmtSYCL.h
index 79ac88532e143..cd682f4cea594 100644
--- a/clang/include/clang/AST/StmtSYCL.h
+++ b/clang/include/clang/AST/StmtSYCL.h
@@ -105,12 +105,19 @@ class UnresolvedSYCLKernelCallStmt : public Stmt {
   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.
+  // will be synthesized during template instantiation of the host code.
   Expr *KernelLaunchIdExpr = nullptr;
-
-  UnresolvedSYCLKernelCallStmt(CompoundStmt *CS, Expr *IdExpr)
+  // Similar to KernelLaunchIdExpr HandleSYCLSpecialParamsIdExpr stores an
+  // UnresolvedLookupExpr or UnresolvedMemberExpr corresponding to the fuction
+  // handling of special SYCL kernel parameters for which a call will be
+  // synthesized during template instantiation of the device code.
+  Expr *HandleSYCLSpecialParamsIdExpr = nullptr;
+
+  UnresolvedSYCLKernelCallStmt(CompoundStmt *CS, Expr *IdExpr,
+                               Expr *HandleSYCLSpecialParamsIdExpr)
       : Stmt(UnresolvedSYCLKernelCallStmtClass), OriginalStmt(CS),
-        KernelLaunchIdExpr(IdExpr) {}
+        KernelLaunchIdExpr(IdExpr),
+        HandleSYCLSpecialParamsIdExpr(HandleSYCLSpecialParamsIdExpr) {}
 
   void setOriginalStmt(CompoundStmt *CS) { OriginalStmt = CS; }
 
@@ -118,12 +125,13 @@ class UnresolvedSYCLKernelCallStmt : public Stmt {
 
 public:
   static UnresolvedSYCLKernelCallStmt *Create(const ASTContext &C,
-                                              CompoundStmt *CS, Expr *IdExpr) {
-    return new (C) UnresolvedSYCLKernelCallStmt(CS, IdExpr);
+                                              CompoundStmt *CS, Expr *IdExpr,
+                                              Expr *SpecArgsExpr) {
+    return new (C) UnresolvedSYCLKernelCallStmt(CS, IdExpr, SpecArgsExpr);
   }
 
   static UnresolvedSYCLKernelCallStmt *CreateEmpty(const ASTContext &C) {
-    return new (C) UnresolvedSYCLKernelCallStmt(nullptr, nullptr);
+    return new (C) UnresolvedSYCLKernelCallStmt(nullptr, nullptr, nullptr);
   }
 
   CompoundStmt *getOriginalStmt() { return cast<CompoundStmt>(OriginalStmt); }
@@ -133,6 +141,10 @@ class UnresolvedSYCLKernelCallStmt : public Stmt {
 
   Expr *getKernelLaunchIdExpr() { return KernelLaunchIdExpr; }
   const Expr *getKernelLaunchIdExpr() const { return KernelLaunchIdExpr; }
+  Expr *getSpecArgsIdExpr() { return HandleSYCLSpecialParamsIdExpr; }
+  const Expr *getSpecArgsIdExpr() const {
+    return HandleSYCLSpecialParamsIdExpr;
+  }
 
   SourceLocation getBeginLoc() const LLVM_READONLY {
     return getOriginalStmt()->getBeginLoc();
diff --git a/clang/include/clang/Basic/Attr.td 
b/clang/include/clang/Basic/Attr.td
index 70b5773f95b08..5f991590638f1 100644
--- a/clang/include/clang/Basic/Attr.td
+++ b/clang/include/clang/Basic/Attr.td
@@ -1744,6 +1744,13 @@ def SYCLSpecialClass: InheritableAttr {
   let Documentation = [SYCLSpecialClassDocs];
 }
 
+def SYCLSpecialKernelParameter : InheritableAttr {
+  let Spellings = [CXX11<"clang", "sycl_special_kernel_parameter">];
+  let Subjects = SubjectList<[CXXRecord]>;
+  let LangOpts = [SYCLHost, SYCLDevice];
+  let Documentation = [Undocumented];
+}
+
 def C11NoReturn : InheritableAttr {
   let Spellings = [CustomKeyword<"_Noreturn">];
   let Subjects = SubjectList<[Function], ErrorDiag>;
diff --git a/clang/include/clang/Sema/ScopeInfo.h 
b/clang/include/clang/Sema/ScopeInfo.h
index f334f58ebd0a7..1e76e3c676385 100644
--- a/clang/include/clang/Sema/ScopeInfo.h
+++ b/clang/include/clang/Sema/ScopeInfo.h
@@ -249,6 +249,10 @@ class FunctionScopeInfo {
   /// to a SYCL kernel launch function in a dependent context.
   Expr *SYCLKernelLaunchIdExpr = nullptr;
 
+  /// An unresolved identifier lookup expression for an implicit call
+  /// to a handling function for SYCL kernel special parameters.
+  Expr *HandleSYCLSpecialParamsIdExpr = 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 4980aa44c3012..268f31d8947cb 100644
--- a/clang/include/clang/Sema/SemaSYCL.h
+++ b/clang/include/clang/Sema/SemaSYCL.h
@@ -83,19 +83,22 @@ class SemaSYCL : public SemaBase {
   /// 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);
+  ExprResult BuildSYCLKernelLaunchIdExpr(FunctionDecl *FD, QualType KernelName,
+                                         StringRef FuncName);
 
   /// 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);
+                                     Expr *LaunchIdExpr,
+                                     Expr *HandleSpecParamsExpr);
 
   /// Builds an UnresolvedSYCLKernelCallStmt to wrap 'Body'. 'LaunchIdExpr'
   /// specifies the lookup result returned by a previous call to
   /// BuildSYCLKernelLaunchIdExpr().
   StmtResult BuildUnresolvedSYCLKernelCallStmt(CompoundStmt *Body,
-                                               Expr *LaunchIdExpr);
+                                               Expr *LaunchIdExpr,
+                                               Expr *HandleSpecParamsExpr);
 };
 
 } // namespace clang
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index eb5b6d65b4d58..744b120a775a0 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -16466,7 +16466,7 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, 
Decl *D,
     const auto *SKEPAttr = FD->getAttr<SYCLKernelEntryPointAttr>();
     if (!SKEPAttr->isInvalidAttr()) {
       ExprResult LaunchIdExpr =
-          SYCL().BuildSYCLKernelLaunchIdExpr(FD, SKEPAttr->getKernelName());
+          SYCL().BuildSYCLKernelLaunchIdExpr(FD, SKEPAttr->getKernelName(), 
"sycl_kernel_launch");
       // 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
@@ -16475,6 +16475,13 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope 
*FnBodyScope, Decl *D,
       // 'LaunchIDExpr' failed, then 'SYCLKernelLaunchIdExpr' will be assigned
       // a null pointer value below; that is expected.
       getCurFunction()->SYCLKernelLaunchIdExpr = LaunchIdExpr.get();
+      if (!LaunchIdExpr.isInvalid() &&
+          !LaunchIdExpr.get()->getType()->isVoidType()) {
+        ExprResult HSPSPIdExpr = SYCL().BuildSYCLKernelLaunchIdExpr(
+            FD, SKEPAttr->getKernelName(),
+            "sycl_handle_special_kernel_parameters");
+        getCurFunction()->HandleSYCLSpecialParamsIdExpr = HSPSPIdExpr.get();
+      }
     }
   }
 
@@ -16690,7 +16697,8 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt 
*Body, bool IsInstantiation,
         // The function body should already be a SYCLKernelCallStmt in this
         // case, but might not be if there were previous errors.
         SR = Body;
-      } else if (!getCurFunction()->SYCLKernelLaunchIdExpr) {
+      } else if (!getCurFunction()->SYCLKernelLaunchIdExpr ||
+                 !getCurFunction()->HandleSYCLSpecialParamsIdExpr) {
         // 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
@@ -16698,11 +16706,13 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt 
*Body, bool IsInstantiation,
         SR = Body;
       } else if (FD->isTemplated()) {
         SR = SYCL().BuildUnresolvedSYCLKernelCallStmt(
-            cast<CompoundStmt>(Body), 
getCurFunction()->SYCLKernelLaunchIdExpr);
+            cast<CompoundStmt>(Body), getCurFunction()->SYCLKernelLaunchIdExpr,
+            getCurFunction()->HandleSYCLSpecialParamsIdExpr);
       } else {
         SR = SYCL().BuildSYCLKernelCallStmt(
             FD, cast<CompoundStmt>(Body),
-            getCurFunction()->SYCLKernelLaunchIdExpr);
+            getCurFunction()->SYCLKernelLaunchIdExpr,
+            getCurFunction()->HandleSYCLSpecialParamsIdExpr);
       }
       // If construction of the replacement body fails, just continue with the
       // original function body. An early error return here is not valid; the
diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index 386651fa691e0..03f86ec1bf480 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -7753,6 +7753,9 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, 
const ParsedAttr &AL,
   case ParsedAttr::AT_SYCLSpecialClass:
     handleSimpleAttribute<SYCLSpecialClassAttr>(S, D, AL);
     break;
+  case ParsedAttr::AT_SYCLSpecialKernelParameter:
+    handleSimpleAttribute<SYCLSpecialKernelParameterAttr>(S, D, AL);
+    break;
   case ParsedAttr::AT_Format:
     handleFormatAttr(S, D, AL);
     break;
diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp
index 112a6e4416df2..b3de40cfdd68c 100644
--- a/clang/lib/Sema/SemaSYCL.cpp
+++ b/clang/lib/Sema/SemaSYCL.cpp
@@ -425,7 +425,8 @@ void SemaSYCL::CheckSYCLEntryPointFunctionDecl(FunctionDecl 
*FD) {
 }
 
 ExprResult SemaSYCL::BuildSYCLKernelLaunchIdExpr(FunctionDecl *FD,
-                                                 QualType KNT) {
+                                                 QualType KNT,
+                                                 StringRef FuncName) {
   // The current context must be the function definition context to ensure
   // that name lookup is performed within the correct scope.
   assert(SemaRef.CurContext == FD && "The current declaration context does not 
"
@@ -440,12 +441,13 @@ ExprResult 
SemaSYCL::BuildSYCLKernelLaunchIdExpr(FunctionDecl *FD,
 
   ASTContext &Ctx = SemaRef.getASTContext();
   IdentifierInfo &SYCLKernelLaunchID =
-      Ctx.Idents.get("sycl_kernel_launch", tok::TokenKind::identifier);
+      Ctx.Idents.get(FuncName, 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.
+  // FIXME: Extend diagnostics for handle special parameters function
   Sema::CodeSynthesisContext CSC;
   CSC.Kind = Sema::CodeSynthesisContext::SYCLKernelLaunchLookup;
   CSC.Entity = FD;
@@ -492,16 +494,316 @@ ExprResult 
SemaSYCL::BuildSYCLKernelLaunchIdExpr(FunctionDecl *FD,
   return IdExpr;
 }
 
+static bool isSyclSpecialType(QualType Ty) {
+  if (const auto *RT = Ty->getAsRecordDecl())
+    return RT->getMostRecentDecl()->hasAttr<SYCLSpecialKernelParameterAttr>();
+  return false;
+}
+
 namespace {
+/// A special visitor to visit subobjects within a type, i.e. fields of a
+/// class or elements of an array. Useful for SYCl because in SYCL kernels are
+/// defined via lambda expressions or named callable objects and kernel
+/// parameters are fields of these. These visitors will be used for diagnosing
+/// invalid kernel arugments as well as for functional transformations.
+class SubobjectVisitor {
+  ASTContext &Ctx;
+
+  // These enable handler execution only when previous Handlers succeed.
+  template <typename... Tn>
+  bool handleField(FieldDecl *FD, QualType FDTy, Tn &&...tn) {
+    bool result = true;
+    (void)std::initializer_list<int>{(result = result && tn(FD, FDTy), 0)...};
+    return result;
+  }
+  template <typename... Tn>
+  bool handleField(const CXXBaseSpecifier &BD, QualType BDTy, Tn &&...tn) {
+    bool result = true;
+    std::initializer_list<int>{(result = result && tn(BD, BDTy), 0)...};
+    return result;
+  }
+
+#define KF_FOR_EACH(FUNC, Item, Qt)                                            
\
+  handleField(Item, Qt, ([&](FieldDecl *FD, QualType FDTy) {                   
\
+                return Handlers.FUNC(FD, FDTy);                                
\
+              })...)
+
+  // Parent contains the FieldDecl or CXXBaseSpecifier that was used to enter
+  // the Wrapper structure that we're currently visiting. Owner is the parent
+  // type (which doesn't exist in cases where it is a FieldDecl in the
+  // 'root'), and Wrapper is the current struct being unwrapped.
+  template <typename ParentTy, typename... HandlerTys>
+  void visitComplexRecord(const CXXRecordDecl *Owner, ParentTy &Parent,
+                          const CXXRecordDecl *Wrapper, QualType RecordTy,
+                          HandlerTys &...Handlers) {
+    (void)std::initializer_list<int>{
+        (Handlers.enterStruct(Owner, Parent, RecordTy), 0)...};
+    visitRecordHelper(Wrapper, Wrapper->bases(), Handlers...);
+    visitRecordHelper(Wrapper, Wrapper->fields(), Handlers...);
+    (void)std::initializer_list<int>{
+        (Handlers.leaveStruct(Owner, Parent, RecordTy), 0)...};
+  }
+
+  template <typename... HandlerTys>
+  void visitArray(const CXXRecordDecl *Owner, FieldDecl *Field,
+                  QualType ArrayTy, HandlerTys &...Handlers) {
+    // TODO add support for simple array visiting, i.e. without entering array
+    // elements.
+    visitComplexArray(Owner, Field, ArrayTy, Handlers...);
+  }
+
+  template <typename ParentTy, typename... HandlerTys>
+  void visitRecord(const CXXRecordDecl *Owner, ParentTy &Parent,
+                   const CXXRecordDecl *Wrapper, QualType RecordTy,
+                   HandlerTys &...Handlers) {
+    // TODO add support for simple record visiting, i.e. without entering 
record
+    // fields.
+    visitComplexRecord(Owner, Parent, Wrapper, RecordTy, Handlers...);
+  }
+
+  template <typename... HandlerTys>
+  void visitRecordHelper(const CXXRecordDecl *Owner,
+                         clang::CXXRecordDecl::base_class_const_range Range,
+                         HandlerTys &...Handlers) {
+    for (const auto &Base : Range) {
+      QualType BaseTy = Base.getType();
+      visitRecord(Owner, Base, BaseTy->getAsCXXRecordDecl(), BaseTy,
+                  Handlers...);
+    }
+  }
+
+  template <typename... HandlerTys>
+  void visitRecordHelper(const CXXRecordDecl *Owner, RecordDecl::field_range,
+                         HandlerTys &...Handlers) {
+    visitRecordFields(Owner, Handlers...);
+  }
+
+  template <typename... HandlerTys>
+  void visitArrayElementImpl(const CXXRecordDecl *Owner, FieldDecl *ArrayField,
+                             QualType ElementTy, uint64_t Index,
+                             HandlerTys &...Handlers) {
+    visitField(Owner, ArrayField, ElementTy, Handlers...);
+  }
+
+  template <typename... HandlerTys>
+  void visitNthArrayElement(const CXXRecordDecl *Owner, FieldDecl *ArrayField,
+                            QualType ElementTy, uint64_t Index,
+                            HandlerTys &...Handlers) {
+    visitArrayElementImpl(Owner, ArrayField, ElementTy, Index, Handlers...);
+  }
+
+  template <typename... HandlerTys>
+  void visitComplexArray(const CXXRecordDecl *Owner, FieldDecl *Field,
+                         QualType ArrayTy, HandlerTys &...Handlers) {
+    // Array workflow is:
+    // handleArrayType
+    // enterArray
+    // visitField (same as before, note that The FieldDecl is the of array
+    // itself, not the element)
+    // ... repeat per element, opt-out for duplicates.
+    // leaveArray
+
+    if (!KF_FOR_EACH(handleArrayType, Field, ArrayTy))
+      return;
+
+    const ConstantArrayType *CAT = Ctx.getAsConstantArrayType(ArrayTy);
+    assert(CAT && "Should only be called on constant-size array.");
+    QualType ET = CAT->getElementType();
+    uint64_t ElemCount = CAT->getSize().getZExtValue();
+
+    (void)std::initializer_list<int>{
+        (Handlers.enterArray(Field, ArrayTy, ET), 0)...};
+
+    for (uint64_t Index = 0; Index < ElemCount; ++Index)
+      visitNthArrayElement(Owner, Field, ET, Index, Handlers...);
+
+    (void)std::initializer_list<int>{
+        (Handlers.leaveArray(Field, ArrayTy, ET), 0)...};
+  }
+
+  template <typename... HandlerTys>
+  void visitField(const CXXRecordDecl *Owner, FieldDecl *Field,
+                  QualType FieldTy, HandlerTys &...Handlers) {
+    if (FieldTy->isStructureOrClassType()) {
+      if (KF_FOR_EACH(handleStructType, Field, FieldTy)) {
+        CXXRecordDecl *RD = FieldTy->getAsCXXRecordDecl();
+        visitRecord(Owner, Field, RD, FieldTy, Handlers...);
+      }
+    } else if (FieldTy->isUnionType())
+      KF_FOR_EACH(handleUnionType, Field, FieldTy);
+    else if (FieldTy->isReferenceType())
+      KF_FOR_EACH(handleReferenceType, Field, FieldTy);
+    else if (FieldTy->isPointerType())
+      KF_FOR_EACH(handlePointerType, Field, FieldTy);
+    else if (FieldTy->isArrayType())
+      visitArray(Owner, Field, FieldTy, Handlers...);
+    else if (FieldTy->isScalarType() || FieldTy->isVectorType())
+      KF_FOR_EACH(handleScalarType, Field, FieldTy);
+    else
+      KF_FOR_EACH(handleOtherType, Field, FieldTy);
+  }
+
+public:
+  SubobjectVisitor(ASTContext &C) : Ctx(C) {}
+
+  template <typename... HandlerTys>
+  void visitRecordBases(const CXXRecordDecl *KernelFunctor,
+                        HandlerTys &...Handlers) {
+    visitRecordHelper(KernelFunctor, KernelFunctor->bases(), Handlers...);
+  }
+
+  template <typename... HandlerTys>
+  void visitRecordFields(const CXXRecordDecl *Owner, HandlerTys &...Handlers) {
+    for (const auto Field : Owner->fields())
+      visitField(Owner, Field, Field->getType(), Handlers...);
+  }
+
+#undef KF_FOR_EACH
+};
+
+class SyclKernelFieldHandlerBase {
+public:
+  virtual bool handleStructType(FieldDecl *, QualType) { return true; }
+  virtual bool handleUnionType(FieldDecl *, QualType) { return true; }
+  virtual bool handleReferenceType(FieldDecl *, QualType) { return true; }
+  virtual bool handlePointerType(FieldDecl *, QualType) { return true; }
+  virtual bool handleArrayType(FieldDecl *, QualType) { return true; }
+  virtual bool handleScalarType(FieldDecl *, QualType) { return true; }
+  // Most handlers shouldn't be handling this, just the field checker.
+  virtual bool handleOtherType(FieldDecl *, QualType) { return true; }
+
+  virtual bool enterStruct(const CXXRecordDecl *, FieldDecl *, QualType) {
+    return true;
+  }
+  virtual bool leaveStruct(const CXXRecordDecl *, FieldDecl *, QualType) {
+    return true;
+  }
+  virtual bool enterStruct(const CXXRecordDecl *, const CXXBaseSpecifier &,
+                           QualType) {
+    return true;
+  }
+  virtual bool leaveStruct(const CXXRecordDecl *, const CXXBaseSpecifier &,
+                           QualType) {
+    return true;
+  }
+  // The following are used for stepping through array elements.
+  virtual bool enterArray(FieldDecl *, QualType, QualType) { return true; }
+  virtual bool leaveArray(FieldDecl *, QualType, QualType) { return true; }
+
+  virtual ~SyclKernelFieldHandlerBase() = default;
+};
+
+// A class to act as the direct base for all the SYCL Kernel related
+// tasks that contains a reference to Sema (and potentially any other
+// universally required data).
+class SyclKernelFieldHandler : public SyclKernelFieldHandlerBase {
+protected:
+  SemaSYCL &SemaSYCLRef;
+  SyclKernelFieldHandler(SemaSYCL &S) : SemaSYCLRef(S) {}
+};
+
+// A type to check the validity of all of the argument types.
+class SyclKernelSpecObjFinder : public SyclKernelFieldHandler {
+  SourceLocation SrcLoc;
+  ValueDecl *SKEPFArgObj;
+  llvm::SmallVector<Expr *, 16> MemberExprBases;
+  llvm::SmallVectorImpl<Expr *> &ResultingArgs;
+
+  bool isArrayElement(const FieldDecl *FD, QualType Ty) const {
+    return !SemaSYCLRef.getASTContext().hasSameType(FD->getType(), Ty);
+  }
+
+public:
+  /// Constructor for the SyclKernelFieldChecker
+  /// \param S The SemaSYCL reference used for diagnostics and context.
+  /// \param FFLoc Free function location, used to report diagnostics
+  explicit SyclKernelSpecObjFinder(SemaSYCL &S, SourceLocation Loc,
+                                   ValueDecl *SKEPFArgObj,
+                                   llvm::SmallVectorImpl<Expr *> 
&ResultingArgs)
+      : SyclKernelFieldHandler(S), SrcLoc(Loc), SKEPFArgObj(SKEPFArgObj),
+        ResultingArgs(ResultingArgs) {
+    QualType KernelObjT = SKEPFArgObj->getType().getNonReferenceType();
+    Expr *Base = SemaSYCLRef.SemaRef.BuildDeclRefExpr(SKEPFArgObj, KernelObjT,
+                                                      VK_LValue, SrcLoc);
+    MemberExprBases.push_back(Base);
+  }
+
+  MemberExpr *buildMemberExpr(Expr *Base, ValueDecl *Member) {
+    DeclAccessPair MemberDAP = DeclAccessPair::make(Member, AS_none);
+    MemberExpr *Result = SemaSYCLRef.SemaRef.BuildMemberExpr(
+        Base, /*IsArrow */ false, SrcLoc, NestedNameSpecifierLoc(),
+        SrcLoc, Member, MemberDAP,
+        /*HadMultipleCandidates*/ false,
+        DeclarationNameInfo(Member->getDeclName(), SrcLoc),
+        Member->getType(), VK_LValue, OK_Ordinary);
+    return Result;
+  }
+  void addFieldMemberExpr(FieldDecl *FD, QualType Ty) {
+    if (!isArrayElement(FD, Ty))
+      MemberExprBases.push_back(buildMemberExpr(MemberExprBases.back(), FD));
+  }
+  void removeFieldMemberExpr(const FieldDecl *FD, QualType Ty) {
+    if (!isArrayElement(FD, Ty))
+      MemberExprBases.pop_back();
+  }
+
+  bool enterStruct(const CXXRecordDecl *, FieldDecl *FD, QualType Ty) final {
+    addFieldMemberExpr(FD, Ty);
+    return true;
+  }
+
+  bool leaveStruct(const CXXRecordDecl *, FieldDecl *FD, QualType Ty) final {
+    if (isSyclSpecialType(Ty)) {
+      ResultingArgs.push_back(MemberExprBases.back());
+    }
+    removeFieldMemberExpr(FD, Ty);
+    return true;
+  }
+
+  bool enterStruct(const CXXRecordDecl *RD, const CXXBaseSpecifier &BS,
+                   QualType) final {
+    CXXCastPath BasePath;
+    QualType DerivedTy = SemaSYCLRef.getASTContext().getCanonicalTagType(RD);
+    QualType BaseTy = BS.getType();
+    SemaSYCLRef.SemaRef.CheckDerivedToBaseConversion(
+        DerivedTy, BaseTy, SrcLoc, SourceRange(), &BasePath,
+        /*IgnoreBaseAccess*/ true);
+    auto Cast = ImplicitCastExpr::Create(
+        SemaSYCLRef.getASTContext(), BaseTy, CK_DerivedToBase,
+        MemberExprBases.back(),
+        /* CXXCastPath=*/&BasePath, VK_LValue, FPOptionsOverride());
+    MemberExprBases.push_back(Cast);
+    return true;
+  }
+
+  bool leaveStruct(const CXXRecordDecl *, const CXXBaseSpecifier &,
+                   QualType) final {
+    MemberExprBases.pop_back();
+    return true;
+  }
+};
+
+static void createArgumentsForSpecialTypes(SmallVectorImpl<Expr *> &Args,
+                                           ValueDecl *KernelArgObj,
+                                           SourceLocation Loc, Sema &SemaRef) {
+  QualType KernelArgObjTy = KernelArgObj->getType();
+  const CXXRecordDecl *KernelArgObjRecord =
+      KernelArgObjTy->getAsCXXRecordDecl();
+  assert(KernelArgObjRecord && "SYCL kernel object is expected");
+  SyclKernelSpecObjFinder Finder(SemaRef.SYCL(), Loc, KernelArgObj, Args);
+  SubobjectVisitor Visitor{SemaRef.getASTContext()};
+  Visitor.visitRecordBases(KernelArgObjRecord, Finder);
+  Visitor.visitRecordFields(KernelArgObjRecord, Finder);
+}
 
 // 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' 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) {
+static bool 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 && "The current declaration context does not 
"
@@ -540,9 +842,9 @@ bool BuildSYCLKernelLaunchCallArgs(Sema &SemaRef, 
FunctionDecl *FD,
 }
 
 // Constructs the SYCL kernel launch call.
-StmtResult BuildSYCLKernelLaunchCallStmt(Sema &SemaRef, FunctionDecl *FD,
-                                         const SYCLKernelInfo *SKI,
-                                         Expr *IdExpr, SourceLocation Loc) {
+StmtResult BuildSYCLKernelLaunchCallStmt(
+    Sema &SemaRef, FunctionDecl *FD, const SYCLKernelInfo *SKI, Expr *IdExpr,
+    SourceLocation Loc, SmallVectorImpl<QualType> &SpecialArgTys) {
   SmallVector<Stmt *> Stmts;
   // IdExpr may be null if name lookup failed.
   if (IdExpr) {
@@ -574,8 +876,38 @@ StmtResult BuildSYCLKernelLaunchCallStmt(Sema &SemaRef, 
FunctionDecl *FD,
           SemaRef.BuildCallExpr(SemaRef.getCurScope(), IdExpr, Loc, Args, Loc);
       if (LaunchResult.isInvalid())
         return StmtError();
-
-      Stmts.push_back(SemaRef.MaybeCreateExprWithCleanups(LaunchResult).get());
+      Expr *BaseForSubsCall =
+          SemaRef.MaybeCreateExprWithCleanups(LaunchResult).get();
+      if (!BaseForSubsCall->getType()->isVoidType()) {
+        // FIXME: diagnose that sycl_kernel_launch call returned a callable
+        // object. Default diagnostic here is very uncldear
+        llvm::SmallVector<Expr *, 12> SpecialArgs;
+        for (auto Param : FD->parameters()) {
+          if (Param->getType()->isRecordType())
+            createArgumentsForSpecialTypes(SpecialArgs, Param, Loc, SemaRef);
+        }
+        ExprResult Result = SemaRef.BuildCallExpr(
+            SemaRef.getCurScope(), BaseForSubsCall, Loc, SpecialArgs, Loc);
+        if (Result.isInvalid())
+          return StmtError();
+
+        // Now gather types for device code generation. Callable object 
returned
+        // by sycl_kernel_launch call returns type_list object whose template
+        // arguments describe types of additional kernel arguments required for
+        // special objects, i.e. SYCL accessors/samplers/streams etc.
+        QualType Ty = Result.get()->getType();
+        // FIXME: that also needs to be diagnosed somewhere.
+        auto *TST = Ty->getAs<TemplateSpecializationType>();
+        if (!TST)
+          return StmtError();
+        for (auto Arg : TST->template_arguments()) {
+          SpecialArgTys.push_back(Arg.getAsType().getCanonicalType());
+        }
+
+        Stmts.push_back(SemaRef.MaybeCreateExprWithCleanups(Result).get());
+      } else {
+        Stmts.push_back(BaseForSubsCall);
+      }
     }
   }
 
@@ -638,14 +970,21 @@ class OutlinedFunctionDeclBodyInstantiator
   FunctionDecl *FD;
 };
 
-OutlinedFunctionDecl *BuildSYCLKernelEntryPointOutline(Sema &SemaRef,
-                                                       FunctionDecl *FD,
-                                                       CompoundStmt *Body) {
+DeclResult
+BuildSYCLKernelEntryPointOutline(Sema &SemaRef, FunctionDecl *FD,
+                                 CompoundStmt *Body,
+                                 SmallVectorImpl<QualType> &SpecialArgTys,
+                                 Expr *IdExpr, SourceLocation Loc) {
   using ParmDeclMap = OutlinedFunctionDeclBodyInstantiator::ParmDeclMap;
   ParmDeclMap ParmMap;
 
   OutlinedFunctionDecl *OFD = OutlinedFunctionDecl::Create(
-      SemaRef.getASTContext(), FD, FD->getNumParams());
+      SemaRef.getASTContext(), FD, FD->getNumParams() + SpecialArgTys.size());
+
+  // CurContext is skep-attributed function but we're actually building device
+  // version of it which is a different DeclContext, so push it on the stack.
+  Sema::ContextRAII SavedContext(SemaRef, OFD);
+
   unsigned i = 0;
   for (ParmVarDecl *PVD : FD->parameters()) {
     ImplicitParamDecl *IPD = ImplicitParamDecl::Create(
@@ -655,21 +994,96 @@ OutlinedFunctionDecl 
*BuildSYCLKernelEntryPointOutline(Sema &SemaRef,
     ParmMap[PVD] = IPD;
     ++i;
   }
-
   OutlinedFunctionDeclBodyInstantiator OFDBodyInstantiator(SemaRef, ParmMap,
                                                            FD);
-  Stmt *OFDBody = OFDBodyInstantiator.TransformStmt(Body).get();
+  Stmt *TransformedBody = OFDBodyInstantiator.TransformStmt(Body).get();
+
+  // Create kernel parameters for special types and create arguments to
+  // sycl_handle_special_kernel_parameters call.
+  // This is synthesizing the following pseudo-code:
+  // void kernel-entry-point(lambda-from-f kernelFunc, buffer_t* X, int Y) {
+  //   
sycl_handle_special_kernel_parameters<kernel-name-type>(kernelFunc.sout)(X, Y);
+  //   {
+  //     // This is copied body of the orignal skep-attributed function.
+  //     kernelFunc();
+  //   }
+  // }
+  // where sout is has type marked with sycl_special_kernel_parameter 
attribute.
+  Stmt *OFDBody;
+  if (IdExpr && !SpecialArgTys.empty()) {
+    SmallVector<Expr *, 8> HandleArgs;
+    for (unsigned I = 0; I < FD->getNumParams(); ++I) {
+      auto Param = OFD->getParam(I);
+      if (Param->getType()->isRecordType())
+        createArgumentsForSpecialTypes(HandleArgs, Param, Loc, SemaRef);
+    }
+
+    // FIXME add better diagnosing.
+    // Sema::CodeSynthesisContext CSC;
+    // CSC.Kind =
+    // Sema::CodeSynthesisContext::SYCLKernelLaunchOverloadResolution;
+    // CSC.Entity = FD;
+    // CSC.CallArgs = Args.data();
+    // CSC.NumCallArgs = Args.size();
+    // Sema::ScopedCodeSynthesisContext ScopedCSC(SemaRef, CSC);
+
+    // Handle args for sycl_handle_special_kernel_parameters call, these are
+    // coming from subobjects with sycl_special_kernel_parameter attribute
+    // within skep-attributed function arguments, SpecialArgs are additional 
kernel
+    // arguments that are needed to initialize special subobjects and they go
+    // to the subsequent call.
+    SmallVector<Expr *, 12> SpecialArgs;
+    for (auto QT : SpecialArgTys) {
+      ImplicitParamDecl *IPD = ImplicitParamDecl::Create(
+          SemaRef.getASTContext(), OFD, SourceLocation(),
+          &SemaRef.getASTContext().Idents.get("idk"), QT,
+          ImplicitParamKind::Other);
+      OFD->setParam(i, IPD);
+      ++i;
+      ExprResult Arg =
+          SemaRef.BuildDeclRefExpr(IPD, QT, VK_LValue, SourceLocation());
+      assert(!Arg.isInvalid() && "synthesized code generation failed?");
+      SpecialArgs.push_back(Arg.get());
+    }
+
+    // This generates 
sycl_handle_special_kernel_parameters<kernel-name-type>(kernelFunc.sout)
+    ExprResult FirstHandleCallResult = SemaRef.BuildCallExpr(
+        SemaRef.getCurScope(), IdExpr, Loc, HandleArgs, Loc);
+    if (FirstHandleCallResult.isInvalid())
+      return true;
+    // FIXME: diagnose that sycl_special_kernel_parameter call returned a
+    // callable object. Default diagnostic here is very uncldear
+
+    Expr *BaseForSubsCall =
+        SemaRef.MaybeCreateExprWithCleanups(FirstHandleCallResult).get();
+    ExprResult Result = SemaRef.BuildCallExpr(
+        SemaRef.getCurScope(), BaseForSubsCall, Loc, SpecialArgs, Loc);
+    if (Result.isInvalid())
+      return true;
+
+    SmallVector<Stmt *> Stmts;
+    // Make sure to push kernel argument processing result first, before the
+    // transformed body of skep-attributed function.
+    Stmts.push_back(SemaRef.MaybeCreateExprWithCleanups(Result).get());
+    Stmts.push_back(TransformedBody);
+    OFDBody = CompoundStmt::Create(SemaRef.getASTContext(), Stmts,
+                                   FPOptionsOverride(), Loc, Loc);
+  } else {
+    OFDBody = TransformedBody;
+  }
+
   OFD->setBody(OFDBody);
   OFD->setNothrow();
-
   return OFD;
+
 }
 
 } // unnamed namespace
 
 StmtResult SemaSYCL::BuildSYCLKernelCallStmt(FunctionDecl *FD,
                                              CompoundStmt *Body,
-                                             Expr *LaunchIdExpr) {
+                                             Expr *LaunchIdExpr,
+                                             Expr *HandleSpecParamsExpr) {
   assert(!FD->isInvalidDecl());
   assert(!FD->isTemplated());
   assert(FD->hasPrototype());
@@ -690,28 +1104,31 @@ StmtResult 
SemaSYCL::BuildSYCLKernelCallStmt(FunctionDecl *FD,
       getASTContext().getSYCLKernelInfo(SKEPAttr->getKernelName());
   assert(declaresSameEntity(SKI.getKernelEntryPointDecl(), FD) &&
          "SYCL kernel name conflict");
-
-  // Build the outline of the synthesized device entry point function.
-  OutlinedFunctionDecl *OFD =
-      BuildSYCLKernelEntryPointOutline(SemaRef, FD, Body);
-  assert(OFD);
-
+  SourceLocation Loc = Body->getLBracLoc();
   // 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);
+  llvm::SmallVector<QualType, 8> SpecialArgTys;
+  StmtResult LaunchResult = BuildSYCLKernelLaunchCallStmt(
+      SemaRef, FD, &SKI, LaunchIdExpr, Loc, SpecialArgTys);
+
   if (LaunchResult.isInvalid())
     return StmtError();
 
-  Stmt *NewBody =
-      new (getASTContext()) SYCLKernelCallStmt(Body, LaunchResult.get(), OFD);
+  // Build the outline of the synthesized device entry point function.
+  DeclResult OFD = BuildSYCLKernelEntryPointOutline(
+      SemaRef, FD, Body, SpecialArgTys, HandleSpecParamsExpr, Loc);
+
+  if (OFD.isInvalid())
+    return StmtError();
+
+  Stmt *NewBody = new (getASTContext()) SYCLKernelCallStmt(
+      Body, LaunchResult.get(), cast<OutlinedFunctionDecl>(OFD.get()));
 
   return NewBody;
 }
 
-StmtResult SemaSYCL::BuildUnresolvedSYCLKernelCallStmt(CompoundStmt *Body,
-                                                       Expr *LaunchIdExpr) {
-  return UnresolvedSYCLKernelCallStmt::Create(SemaRef.getASTContext(), Body,
-                                              LaunchIdExpr);
+StmtResult SemaSYCL::BuildUnresolvedSYCLKernelCallStmt(
+    CompoundStmt *Body, Expr *LaunchIdExpr, Expr *HandleSpecParamsExpr) {
+  return UnresolvedSYCLKernelCallStmt::Create(
+      SemaRef.getASTContext(), Body, LaunchIdExpr, HandleSpecParamsExpr);
 }
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 40187f71231bd..f4a8d7736438d 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -13148,13 +13148,18 @@ StmtResult 
TreeTransform<Derived>::TransformUnresolvedSYCLKernelCallStmt(
   if (IdExpr.isInvalid())
     return StmtError();
 
+  ExprResult SpecArgsIdExpr =
+      getDerived().TransformExpr(S->getSpecArgsIdExpr());
+  if (SpecArgsIdExpr.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());
+      IdExpr.get(), SpecArgsIdExpr.get());
   if (SR.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 1047302d8f36e..5a31981a85ed4 100644
--- a/clang/test/ASTSYCL/ast-dump-sycl-kernel-call-stmt.cpp
+++ b/clang/test/ASTSYCL/ast-dump-sycl-kernel-call-stmt.cpp
@@ -37,6 +37,9 @@ template<int> struct K {
 template<typename KernelName, typename... Ts>
 void sycl_kernel_launch(const char *, Ts...) {}
 
+template<typename KernelName, typename... Ts>
+void sycl_handle_special_kernel_parameters(Ts...) {}
+
 [[clang::sycl_kernel_entry_point(KN<1>)]]
 void skep1() {
 }
diff --git a/clang/test/ASTSYCL/ast-dump-sycl-kernel-decomposition.cpp 
b/clang/test/ASTSYCL/ast-dump-sycl-kernel-decomposition.cpp
new file mode 100644
index 0000000000000..67e7b0266dc32
--- /dev/null
+++ b/clang/test/ASTSYCL/ast-dump-sycl-kernel-decomposition.cpp
@@ -0,0 +1,141 @@
+// Tests without serialization:
+// RUN: %clang_cc1 -std=c++17 -triple spirv64-unknown-unknown -fsycl-is-device 
\
+// RUN:   -ast-dump %s \
+// RUN:   | FileCheck %s
+// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-unknown -fsycl-is-host \
+// RUN:   -ast-dump %s \
+// RUN:   | FileCheck %s
+
+// Thes test validates the AST body produced for functions declared with the
+// sycl_kernel_entry_point attribute in case an argument of such function
+// contains an object that requires decomposition.
+
+// CHECK: TranslationUnitDecl {{.*}}
+
+// A unique kernel name type is required for each declared kernel entry point.
+template<int> struct KN;
+
+struct [[clang::sycl_special_kernel_parameter]] EmptySpecial {
+  int data;
+};
+
+template<typename T>
+struct Wrapper {
+ T data;
+ int *data1;
+};
+
+template<typename T>
+auto set_kernel_arg(const T &t) {
+  return t;
+}
+
+auto set_kernel_arg(EmptySpecial &a) {
+  return a.data;
+}
+
+template<typename KernelName, typename... Ts>
+auto sycl_handle_special_kernel_parameters(Ts...) {
+  return [](auto ...Args){ return; };
+}
+
+template<typename... Ts>
+struct type_list {};
+
+template <typename KernelName, typename... Ts>
+auto sycl_kernel_launch(const char *, Ts...) {
+
+    return [&](auto&&... extra_host_args) {
+      return type_list<decltype(set_kernel_arg(extra_host_args))...>{};
+  };
+}
+
+
+template <typename KN, typename KT>
+[[clang::sycl_kernel_entry_point(KN)]] void k(KT Kernel) {
+  Kernel();
+}
+// CHECK:      |-FunctionTemplateDecl {{.*}} k{{.*}}
+// CHECK-NEXT: | |-TemplateTypeParmDecl {{.*}} referenced typename depth 0 
index 0 KN
+// CHECK-NEXT: | |-TemplateTypeParmDecl {{.*}} referenced typename depth 0 
index 1 KT
+// CHECK-NEXT: | |-FunctionDecl {{.*}} k 'void (KT)'
+// CHECK-NEXT: | | |-ParmVarDecl {{.*}} referenced Kernel 'KT'
+// CHECK-NEXT: | | |-UnresolvedSYCLKernelCallStmt {{.*}}
+// CHECK-NEXT: | | | |-CompoundStmt {{.*}}
+// CHECK-NEXT: | | | | `-CallExpr {{.*}} '<dependent type>'
+// CHECK-NEXT: | | | |  `-DeclRefExpr {{.*}} 'KT' lvalue ParmVar {{.*}} 
'Kernel' 'KT'
+// CHECK-NEXT: | | | |-UnresolvedLookupExpr {{.*}} '<dependent type>' lvalue 
(ADL) = 'sycl_kernel_launch' {{.*}}
+// CHECK-NEXT: | | | | `-TemplateArgument type 'KN':'type-parameter-0-0'
+// CHECK-NEXT: | | | |   `-TemplateTypeParmType {{.*}} 'KN' dependent depth 0 
index 0
+// CHECK-NEXT: | | | |     `-TemplateTypeParm {{.*}} 'KN'
+// CHECK-NEXT: | | | `-UnresolvedLookupExpr {{.*}} '<dependent type>' lvalue 
(ADL) = 'sycl_handle_special_kernel_parameters' {{.*}}
+// CHECK-NEXT: | | |   `-TemplateArgument type 'KN':'type-parameter-0-0'
+// CHECK-NEXT: | | |     `-TemplateTypeParmType {{.*}} 'KN' dependent depth 0 
index 0
+// CHECK-NEXT: | | |       `-TemplateTypeParm {{.*}} 'KN'
+// CHECK-NEXT: | |  `-SYCLKernelEntryPointAttr {{.*}} KN
+// CHECK-NEXT: | `-FunctionDecl {{.*}} used k {{.*}} implicit_instantiation 
instantiated_from {{.*}}
+// CHECK-NEXT: |   |-TemplateArgument type 'KN<0>'
+// CHECK-NEXT: |   | `-RecordType {{.*}} 'KN<0>' canonical
+// CHECK-NEXT: |   |   `-ClassTemplateSpecialization {{.*}} 'KN'
+// CHECK-NEXT: |   |-TemplateArgument type '{{.*}}'
+// CHECK-NEXT: |   | `-RecordType {{.*}} canonical
+// CHECK-NEXT: |   |   `-CXXRecord {{.*}}
+// CHECK-NEXT: |   |-ParmVarDecl {{.*}} used Kernel {{.*}}
+// CHECK-NEXT: |   |-SYCLKernelCallStmt {{.*}}
+// CHECK-NEXT: |   | |-CompoundStmt {{.*}}
+// CHECK-NEXT: |   | | `-CXXOperatorCallExpr {{.*}} 'void' '()'
+// CHECK-NEXT: |   | |   |-ImplicitCastExpr {{.*}} 'void (*)() const' 
<FunctionToPointerDecay>
+// CHECK-NEXT: |   | |   | `-DeclRefExpr {{.*}} 'void () const' lvalue 
CXXMethod {{.*}} 'operator()' 'void () const'
+// CHECK-NEXT: |   | |   `-ImplicitCastExpr {{.*}} 'const {{.*}}' lvalue <NoOp>
+// CHECK-NEXT: |   | |     `-DeclRefExpr {{.*}} lvalue ParmVar {{.*}} 'Kernel' 
{{.*}}
+// CHECK-NEXT: |   | |-CompoundStmt {{.*}}
+// CHECK-NEXT: |   | | `-ExprWithCleanups {{.*}} 'type_list<{{.*}}>'
+// CHECK-NEXT: |   | |   `-CXXOperatorCallExpr {{.*}} 'type_list<{{.*}}>' '()'
+// CHECK-NEXT: |   | |     |-ImplicitCastExpr {{.*}} 'type_list<{{.*}}> 
(*)(EmptySpecial &) const' <FunctionToPointerDecay>
+// CHECK-NEXT: |   | |     | `-DeclRefExpr {{.*}} 'type_list<{{.*}}> 
(EmptySpecial &) const' lvalue CXXMethod {{.*}} 'operator()' '{{.*}}'
+// CHECK-NEXT: |   | |     |-ImplicitCastExpr {{.*}} 'const {{.*}}' lvalue 
<NoOp>
+// CHECK-NEXT: |   | |     | `-MaterializeTemporaryExpr {{.*}} '{{.*}}' lvalue
+// CHECK-NEXT: |   | |     |   `-CallExpr {{.*}} '{{.*}}'
+// CHECK-NEXT: |   | |     |     |-ImplicitCastExpr {{.*}} '{{.*}}' 
<FunctionToPointerDecay>
+// CHECK-NEXT: |   | |     |     | `-DeclRefExpr {{.*}} '{{.*}}' lvalue 
Function {{.*}} 'sycl_kernel_launch' {{.*}}
+// CHECK-NEXT: |   | |     |     |-ImplicitCastExpr {{.*}} 'const char *' 
<ArrayToPointerDecay>
+// CHECK-NEXT: |   | |     |     | `-StringLiteral {{.*}} 'const char[14]' 
lvalue "_ZTS2KNILi0EE"
+// CHECK-NEXT: |   | |     |     `-CXXConstructExpr {{.*}} '{{.*}}' 'void 
({{.*}} &&) noexcept'
+// CHECK-NEXT: |   | |     |       `-ImplicitCastExpr {{.*}} '{{.*}}' xvalue 
<NoOp>
+// CHECK-NEXT: |   | |     |         `-DeclRefExpr {{.*}} lvalue ParmVar 
{{.*}} 'Kernel' {{.*}}
+// CHECK-NEXT: |   | |     `-MemberExpr {{.*}} 'EmptySpecial' lvalue .data 
{{.*}}
+// CHECK-NEXT: |   | |       `-MemberExpr {{.*}} 'Wrapper<EmptySpecial>' 
lvalue . {{.*}}
+// CHECK-NEXT: |   | |         `-DeclRefExpr {{.*}} lvalue ParmVar {{.*}} 
'Kernel' {{.*}}
+// CHECK-NEXT: |   | `-OutlinedFunctionDecl {{.*}}
+// CHECK-NEXT: |   |   |-ImplicitParamDecl {{.*}} implicit used Kernel {{.*}}
+// CHECK-NEXT: |   |   |-ImplicitParamDecl {{.*}} implicit used idk {{.*}}
+// CHECK-NEXT: |   |   `-CompoundStmt {{.*}}
+// CHECK-NEXT: |   |     |-ExprWithCleanups {{.*}} 'void'
+// CHECK-NEXT: |   |     | `-CXXOperatorCallExpr {{.*}} 'void' '()'
+// CHECK-NEXT: |   |     |   |-ImplicitCastExpr {{.*}} 'void (*)(int) const' 
<FunctionToPointerDecay>
+// CHECK-NEXT: |   |     |   | `-DeclRefExpr {{.*}} 'void (int) const' lvalue 
CXXMethod {{.*}} 'operator()' '{{.*}}'
+// CHECK-NEXT: |   |     |   |-ImplicitCastExpr {{.*}} 'const {{.*}}' lvalue 
<NoOp>
+// CHECK-NEXT: |   |     |   | `-MaterializeTemporaryExpr {{.*}} '{{.*}}' 
lvalue
+// CHECK-NEXT: |   |     |   |   `-CallExpr {{.*}} '{{.*}}'
+// CHECK-NEXT: |   |     |   |     |-ImplicitCastExpr {{.*}} '{{.*}}' 
<FunctionToPointerDecay>
+// CHECK-NEXT: |   |     |   |     | `-DeclRefExpr {{.*}} '{{.*}}' lvalue 
Function {{.*}} 'sycl_handle_special_kernel_parameters' {{.*}}
+// CHECK-NEXT: |   |     |   |     `-CXXConstructExpr {{.*}} 'EmptySpecial' 
'void (const EmptySpecial &) noexcept'
+// CHECK-NEXT: |   |     |   |       `-ImplicitCastExpr {{.*}} 'const 
EmptySpecial' lvalue <NoOp>
+// CHECK-NEXT: |   |     |   |         `-MemberExpr {{.*}} 'EmptySpecial' 
lvalue .data {{.*}}
+// CHECK-NEXT: |   |     |   |           `-MemberExpr {{.*}} 
'Wrapper<EmptySpecial>' lvalue . {{.*}}
+// CHECK-NEXT: |   |     |   |             `-DeclRefExpr {{.*}} lvalue 
ImplicitParam {{.*}} 'Kernel' {{.*}}
+// CHECK-NEXT: |   |     |   `-ImplicitCastExpr {{.*}} 'int' <LValueToRValue>
+// CHECK-NEXT: |   |     |     `-DeclRefExpr {{.*}} 'int' lvalue ImplicitParam 
{{.*}} 'idk' 'int'
+// CHECK-NEXT: |   |     `-CompoundStmt {{.*}}
+// CHECK-NEXT: |   |       `-CXXOperatorCallExpr {{.*}} 'void' '()'
+// CHECK-NEXT: |   |         |-ImplicitCastExpr {{.*}} 'void (*)() const' 
<FunctionToPointerDecay>
+// CHECK-NEXT: |   |         | `-DeclRefExpr {{.*}} 'void () const' lvalue 
CXXMethod {{.*}} 'operator()' 'void () const'
+// CHECK-NEXT: |   |         `-ImplicitCastExpr {{.*}} 'const {{.*}}' lvalue 
<NoOp>
+// CHECK-NEXT: |   |           `-DeclRefExpr {{.*}} lvalue ImplicitParam 
{{.*}} 'Kernel' {{.*}}
+// CHECK-NEXT: |   `-SYCLKernelEntryPointAttr {{.*}} struct KN<0>
+
+void case1() {
+    Wrapper<EmptySpecial> KernelArg;
+    k<KN<0>>([KernelArg](){});
+}
+// CHECK: `-FunctionDecl {{.*}} case1 '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 cf7db46b3567e..b8df861fb5e1e 100644
--- a/clang/test/ASTSYCL/ast-dump-sycl-kernel-entry-point.cpp
+++ b/clang/test/ASTSYCL/ast-dump-sycl-kernel-entry-point.cpp
@@ -31,6 +31,9 @@ template<int, int=0> struct KN;
 template<typename KernelName, typename... Ts>
 void sycl_kernel_launch(const char *, Ts... Args) {}
 
+template<typename KernelName, typename... Ts>
+void sycl_handle_special_kernel_parameters(Ts...) {}
+
 [[clang::sycl_kernel_entry_point(KN<1>)]]
 void skep1() {
 }
diff --git a/clang/test/ASTSYCL/ast-print-sycl-kernel-call.cpp 
b/clang/test/ASTSYCL/ast-print-sycl-kernel-call.cpp
index 5adaa367ed9c1..f32b931205042 100644
--- a/clang/test/ASTSYCL/ast-print-sycl-kernel-call.cpp
+++ b/clang/test/ASTSYCL/ast-print-sycl-kernel-call.cpp
@@ -1,6 +1,9 @@
 // RUN: %clang_cc1 -fsycl-is-host -ast-print %s -o - | FileCheck %s
 // RUN: %clang_cc1 -fsycl-is-device -ast-print %s -o - | FileCheck %s
 
+template<typename KernelName, typename... Ts>
+void sycl_handle_special_kernel_parameters(Ts...) {}
+
 struct sycl_kernel_launcher {
   template<typename KernelName, typename... Ts>
   void sycl_kernel_launch(const char *, Ts...) {}
diff --git a/clang/test/CodeGenSYCL/function-attrs.cpp 
b/clang/test/CodeGenSYCL/function-attrs.cpp
index 60d3cf10055ec..efb0081484522 100644
--- a/clang/test/CodeGenSYCL/function-attrs.cpp
+++ b/clang/test/CodeGenSYCL/function-attrs.cpp
@@ -29,6 +29,9 @@ int foo() {
 template <typename Name, typename... Ts>
 void sycl_kernel_launch(Ts...) {}
 
+template <typename Name, typename... Ts>
+void sycl_handle_special_kernel_parameters(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/CodeGenSYCL/kernel-arg-decomposition.cpp 
b/clang/test/CodeGenSYCL/kernel-arg-decomposition.cpp
new file mode 100644
index 0000000000000..b7aa38cc9a1cb
--- /dev/null
+++ b/clang/test/CodeGenSYCL/kernel-arg-decomposition.cpp
@@ -0,0 +1,96 @@
+// RUN: %clang_cc1 -fsycl-is-host -emit-llvm -triple x86_64-unknown-linux-gnu 
-std=c++17 %s -o - | FileCheck --check-prefixes=CHECK-HOST %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 %s
+
+// A unique kernel name type is required for each declared kernel entry point.
+template<int> struct KN;
+
+struct [[clang::sycl_special_kernel_parameter]] EmptySpecial {
+  int data;
+};
+
+template<typename T>
+struct Wrapper {
+ T data;
+ int *data1;
+};
+
+template<typename T>
+auto set_kernel_arg(const T &t) {
+  return t;
+}
+
+auto set_kernel_arg(EmptySpecial &a) {
+  return a.data;
+}
+
+template<typename KernelName, typename... Ts>
+auto sycl_handle_special_kernel_parameters(Ts...) {
+  return [](auto ...Args){ return; };
+}
+
+template<typename... Ts>
+struct type_list {};
+
+template <typename KernelName, typename... Ts>
+auto sycl_kernel_launch(const char *, Ts...) {
+
+    return [&](auto&&... extra_host_args) {
+      return type_list<decltype(set_kernel_arg(extra_host_args))...>{};
+  };
+}
+
+
+template <typename KN, typename KT>
+[[clang::sycl_kernel_entry_point(KN)]] void kernel_entry_point(KT Kernel) {
+  Kernel();
+}
+
+void case1() {
+    Wrapper<EmptySpecial> KernelArg;
+    kernel_entry_point<KN<0>>([KernelArg](){});
+}
+
+// CHECK-HOST-LABEL: define internal void 
@_Z18kernel_entry_pointI2KNILi0EEZ5case1vEUlvE_EvT0_(
+// CHECK-HOST-SAME: i32 [[KERNEL_COERCE0:%.*]], ptr [[KERNEL_COERCE1:%.*]])
+// CHECK-HOST:  [[ENTRY:.*:]]
+// CHECK-HOST-NEXT:    [[KERNEL:%.*]] = alloca [[CLASS_ANON:%.*]], align 8
+// CHECK-HOST-NEXT:    [[REF_TMP:%.*]] = alloca [[CLASS_ANON_0:%.*]], align 1
+// CHECK-HOST-NEXT:    [[AGG_TMP:%.*]] = alloca [[CLASS_ANON]], align 8
+// CHECK-HOST-NEXT:    [[UNDEF_AGG_TMP:%.*]] = alloca [[CLASS_ANON_0]], align 1
+// CHECK-HOST-NEXT:    [[UNDEF_AGG_TMP1:%.*]] = alloca 
[[STRUCT_TYPE_LIST:%.*]], align 1
+// CHECK-HOST-NEXT:    [[TMP0:%.*]] = getelementptr inbounds nuw { i32, ptr }, 
ptr [[KERNEL]], i32 0, i32 0
+// CHECK-HOST-NEXT:    store i32 [[KERNEL_COERCE0]], ptr [[TMP0]], align 8
+// CHECK-HOST-NEXT:    [[TMP1:%.*]] = getelementptr inbounds nuw { i32, ptr }, 
ptr [[KERNEL]], i32 0, i32 1
+// CHECK-HOST-NEXT:    store ptr [[KERNEL_COERCE1]], ptr [[TMP1]], align 8
+// CHECK-HOST-NEXT:    call void @llvm.memcpy.p0.p0.i64(ptr align 8 
[[AGG_TMP]], ptr align 8 [[KERNEL]], i64 16, i1 false)
+// CHECK-HOST-NEXT:    [[TMP2:%.*]] = getelementptr inbounds nuw { i32, ptr }, 
ptr [[AGG_TMP]], i32 0, i32 0
+// CHECK-HOST-NEXT:    [[TMP3:%.*]] = load i32, ptr [[TMP2]], align 8
+// CHECK-HOST-NEXT:    [[TMP4:%.*]] = getelementptr inbounds nuw { i32, ptr }, 
ptr [[AGG_TMP]], i32 0, i32 1
+// CHECK-HOST-NEXT:    [[TMP5:%.*]] = load ptr, ptr [[TMP4]], align 8
+// CHECK-HOST-NEXT:    call void 
@_Z18sycl_kernel_launchI2KNILi0EEJZ5case1vEUlvE_EEDaPKcDpT0_(ptr noundef @.str, 
i32 [[TMP3]], ptr [[TMP5]])
+// CHECK-HOST-NEXT:    [[TMP6:%.*]] = getelementptr inbounds nuw 
[[CLASS_ANON]], ptr [[KERNEL]], i32 0, i32 0
+// CHECK-HOST-NEXT:    [[DATA:%.*]] = getelementptr inbounds nuw 
[[STRUCT_WRAPPER:%.*]], ptr [[TMP6]], i32 0, i32 0
+// CHECK-HOST-NEXT:    call void 
@_ZZ18sycl_kernel_launchI2KNILi0EEJZ5case1vEUlvE_EEDaPKcDpT0_ENKUlDpOT_E_clIJR12EmptySpecialEEEDaS9_(ptr
 noundef nonnull align 1 dereferenceable(1) [[REF_TMP]], ptr noundef nonnull 
align 4 dereferenceable(4) [[DATA]])
+// CHECK-HOST-NEXT:    ret void
+
+// CHECK-DEVICE: define spir_kernel void @_ZTS2KNILi0EE(ptr noundef 
byval(%class.anon) align 8 [[KERNEL:%.*]], i32 noundef [[IDK:%.*]])
+// CHECK-DEVICE:  [[ENTRY:.*:]]
+// CHECK-DEVICE:    [[IDK_ADDR:%.*]] = alloca i32, align 4
+// CHECK-DEVICE:    [[REF_TMP:%.*]] = alloca [[CLASS_ANON_0:%.*]], align 1
+// CHECK-DEVICE:    [[AGG_TMP:%.*]] = alloca [[STRUCT_EMPTYSPECIAL:%.*]], 
align 4
+// CHECK-DEVICE:    [[IDK_ADDR_ASCAST:%.*]] = addrspacecast ptr [[IDK_ADDR]] 
to ptr addrspace(4)
+// CHECK-DEVICE:    [[REF_TMP_ASCAST:%.*]] = addrspacecast ptr [[REF_TMP]] to 
ptr addrspace(4)
+// CHECK-DEVICE:    [[AGG_TMP_ASCAST:%.*]] = addrspacecast ptr [[AGG_TMP]] to 
ptr addrspace(4)
+// CHECK-DEVICE:    [[KERNEL_ASCAST:%.*]] = addrspacecast ptr [[KERNEL]] to 
ptr addrspace(4)
+// CHECK-DEVICE:    store i32 [[IDK]], ptr addrspace(4) [[IDK_ADDR_ASCAST]], 
align 4
+// CHECK-DEVICE:    [[REF_TMP_ASCAST_ASCAST:%.*]] = addrspacecast ptr 
addrspace(4) [[REF_TMP_ASCAST]] to ptr
+// CHECK-DEVICE:    [[TMP0:%.*]] = getelementptr inbounds nuw 
[[CLASS_ANON:%.*]], ptr addrspace(4) [[KERNEL_ASCAST]], i32 0, i32 0
+// CHECK-DEVICE:    [[DATA:%.*]] = getelementptr inbounds nuw 
[[STRUCT_WRAPPER:%.*]], ptr addrspace(4) [[TMP0]], i32 0, i32 0
+// CHECK-DEVICE:    call void @llvm.memcpy.p4.p4.i64(ptr addrspace(4) align 4 
[[AGG_TMP_ASCAST]], ptr addrspace(4) align 8 [[DATA]], i64 4, i1 false)
+// CHECK-DEVICE:    [[AGG_TMP_ASCAST_ASCAST:%.*]] = addrspacecast ptr 
addrspace(4) [[AGG_TMP_ASCAST]] to ptr
+// CHECK-DEVICE:    call spir_func void 
@_Z37sycl_handle_special_kernel_parametersI2KNILi0EEJ12EmptySpecialEEDaDpT0_(ptr
 dead_on_unwind writable sret([[CLASS_ANON_0]]) align 1 
[[REF_TMP_ASCAST_ASCAST]], ptr noundef byval([[STRUCT_EMPTYSPECIAL]]) align 4 
[[AGG_TMP_ASCAST_ASCAST]])
+// CHECK-DEVICE:    [[TMP1:%.*]] = load i32, ptr addrspace(4) 
[[IDK_ADDR_ASCAST]], align 4
+// CHECK-DEVICE:    call spir_func void 
@_ZZ37sycl_handle_special_kernel_parametersI2KNILi0EEJ12EmptySpecialEEDaDpT0_ENKUlDpT_E_clIJiEEEDaS6_(ptr
 addrspace(4) noundef align 1 dereferenceable_or_null(1) [[REF_TMP_ASCAST]], 
i32 noundef [[TMP1]])
+// CHECK-DEVICE:    call spir_func void @_ZZ5case1vENKUlvE_clEv(ptr 
addrspace(4) noundef align 8 dereferenceable_or_null(16) [[KERNEL_ASCAST]])
+// CHECK-DEVICE:    ret void
+
diff --git a/clang/test/CodeGenSYCL/kernel-caller-entry-point.cpp 
b/clang/test/CodeGenSYCL/kernel-caller-entry-point.cpp
index 7af4c83d1ba32..edb58ab57bdbd 100644
--- a/clang/test/CodeGenSYCL/kernel-caller-entry-point.cpp
+++ b/clang/test/CodeGenSYCL/kernel-caller-entry-point.cpp
@@ -33,6 +33,9 @@
 template <typename KernelName, typename... Ts>
 void sycl_kernel_launch(const char *, Ts...) {}
 
+template <typename KernelName, typename... Ts>
+void sycl_handle_special_kernel_parameters(Ts...) {}
+
 struct single_purpose_kernel_name;
 struct single_purpose_kernel {
   void operator()() const {}
diff --git a/clang/test/CodeGenSYCL/sycl-kernel-entry-point-exceptions.cpp 
b/clang/test/CodeGenSYCL/sycl-kernel-entry-point-exceptions.cpp
index 8fe7a148a2f61..56137b934eeca 100644
--- a/clang/test/CodeGenSYCL/sycl-kernel-entry-point-exceptions.cpp
+++ b/clang/test/CodeGenSYCL/sycl-kernel-entry-point-exceptions.cpp
@@ -16,6 +16,9 @@ struct KT {
 };
 
 
+template<typename KN, typename... Ts>
+void sycl_handle_special_kernel_parameters(Ts...) {}
+
 // 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
diff --git a/clang/test/CodeGenSYCL/unique_stable_name_windows_diff.cpp 
b/clang/test/CodeGenSYCL/unique_stable_name_windows_diff.cpp
index c298593e2f1ab..be4fa5482552a 100644
--- a/clang/test/CodeGenSYCL/unique_stable_name_windows_diff.cpp
+++ b/clang/test/CodeGenSYCL/unique_stable_name_windows_diff.cpp
@@ -4,6 +4,9 @@
 template<typename KN, typename... Ts>
 void sycl_kernel_launch(const char *, Ts...) {}
 
+template<typename KN, typename... Ts>
+void sycl_handle_special_kernel_parameters(Ts...) {}
+
 template<typename KN, typename Func>
 [[clang::sycl_kernel_entry_point(KN)]] void kernel(Func F){
   F();
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 45da8c71348b2..49a6de671a8be 100644
--- a/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-appertainment.cpp
+++ b/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-appertainment.cpp
@@ -44,6 +44,9 @@ template<int, int = 0> struct KN;
 template<typename KNT, typename... Ts>
 void sycl_kernel_launch(const char *, Ts...) {}
 
+template<typename KNT, typename... Ts>
+void sycl_handle_special_kernel_parameters(Ts...) {}
+
 
////////////////////////////////////////////////////////////////////////////////
 // Valid declarations.
 
////////////////////////////////////////////////////////////////////////////////
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
index e2854983da552..94a497f6a9cd3 100644
--- 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
@@ -20,6 +20,9 @@ struct type_info {
 template<typename KernelName, typename... Ts>
 void sycl_kernel_launch(const char *, Ts...) {}
 
+template<typename KernelName, typename... Ts>
+void sycl_handle_special_kernel_parameters(Ts...) {}
+
 // A kernel name type template.
 template<int> struct KN;
 
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 b1c9e270a02b8..a8cacbadc009b 100644
--- a/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-grammar.cpp
+++ b/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-grammar.cpp
@@ -14,6 +14,9 @@ template<int N> using TTA = ST<N>; // #TTA-decl
 template<typename KN, typename... Ts>
 void sycl_kernel_launch(const char *, Ts...) {}
 
+template<typename KN, typename... Ts>
+void sycl_handle_special_kernel_parameters(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 05a660e91e82c..a0cbbfad420d7 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
@@ -21,6 +21,9 @@ template<int> struct KN;
 template<typename KN, typename... Ts>
 void sycl_kernel_launch(const char *, Ts...) {}
 
+template<typename KN, typename... Ts>
+void sycl_handle_special_kernel_parameters(Ts...) {}
+
 [[clang::sycl_kernel_entry_point(KN<1>)]]
 void common_test1() {}
 
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 dcea60e016d12..047c6268cfe6c 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
@@ -19,6 +19,9 @@ template<int> struct KN;
 template<typename KN, typename... Ts>
 void sycl_kernel_launch(const char *, Ts...) {}
 
+template<typename KN, typename... Ts>
+void sycl_handle_special_kernel_parameters(Ts...) {}
+
 [[clang::sycl_kernel_entry_point(KN<1>)]]
 void pch_test1() {} // << expected previous declaration note here.
 
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 2abb24cde6663..e8fbd422d4c61 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
@@ -14,6 +14,9 @@ struct S1;
 template<typename KernelName, typename... Ts>
 void sycl_kernel_launch(const char *, Ts...) {}
 
+template<typename KernelName, typename... Ts>
+void sycl_handle_special_kernel_parameters(Ts...) {}
+
 // expected-warning@+3 {{redundant 'clang::sycl_kernel_entry_point' attribute}}
 // expected-note@+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 b39a77bd35878..f4fca91ba1178 100644
--- a/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-sfinae.cpp
+++ b/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-sfinae.cpp
@@ -14,6 +14,9 @@
 template<typename KernelName, typename... Ts>
 void sycl_kernel_launch(const char *, Ts...) {}
 
+template<typename KernelName, typename... Ts>
+void sycl_handle_special_kernel_parameters(Ts...) {}
+
 // 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 2112733b41fc6..7bc4831fcad1d 100644
--- a/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-this.cpp
+++ b/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-this.cpp
@@ -26,6 +26,9 @@ struct type_info {
 template<typename KernelName, typename... Ts>
 void sycl_kernel_launch(const char *, Ts...) {}
 
+template<typename KernelName, typename... Ts>
+void sycl_handle_special_kernel_parameters(Ts...) {}
+
 
////////////////////////////////////////////////////////////////////////////////
 // Valid declarations.
 
////////////////////////////////////////////////////////////////////////////////
diff --git a/clang/test/SemaSYCL/sycl-kernel-launch-ms-compat.cpp 
b/clang/test/SemaSYCL/sycl-kernel-launch-ms-compat.cpp
index cd186a833b024..612ec1b68ecfb 100644
--- a/clang/test/SemaSYCL/sycl-kernel-launch-ms-compat.cpp
+++ b/clang/test/SemaSYCL/sycl-kernel-launch-ms-compat.cpp
@@ -19,6 +19,9 @@ struct KT {
 };
 
 
+template<typename KN, typename... Ts>
+void sycl_handle_special_kernel_parameters(Ts...) {}
+
 namespace ok1 {
   template<typename Derived>
   struct base_handler {
diff --git a/clang/test/SemaSYCL/sycl-kernel-launch.cpp 
b/clang/test/SemaSYCL/sycl-kernel-launch.cpp
index 20d9becb81929..9b8b2696d7b3f 100644
--- a/clang/test/SemaSYCL/sycl-kernel-launch.cpp
+++ b/clang/test/SemaSYCL/sycl-kernel-launch.cpp
@@ -24,6 +24,9 @@ struct KT {
 };
 
 
+template<typename KN, typename... Ts>
+void sycl_handle_special_kernel_parameters(Ts...) {}
+
 // sycl_kernel_launch as function template at namespace scope.
 namespace ok1 {
   template<typename KN, typename... Ts>

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

Reply via email to