https://github.com/hekota updated 
https://github.com/llvm/llvm-project/pull/122820

>From 71ddb5a2b4cc8a9609410b436e896484401f5e90 Mon Sep 17 00:00:00 2001
From: Helena Kotas <heko...@microsoft.com>
Date: Mon, 13 Jan 2025 15:03:12 -0800
Subject: [PATCH 1/8] [HLSL] cbuffer: Create host layout struct and add
 resource handle to AST

Creates layout struct for `cbuffer` in Sema which will contains only 
declarations
contributing to the constant buffer layout. Anything else will be filtered out,
such as static variables decls, struct and function definitions, resources,
or empty struct and zero-sized arrays.

If the constant buffer includes a struct that contains any of the above 
undesirable
declarations, a new version of this struct should be created with these 
declarations
filtered out as well.

The definition of buffer layour struct is added to the HLSLBufferDecl node and 
is followed
by 'cbuffer` resource handle decl referencing the layout struct as its 
contained type.

Fixes #122553
---
 clang/include/clang/AST/Decl.h                |   1 +
 clang/lib/AST/Decl.cpp                        |  13 +
 clang/lib/CodeGen/CGHLSLRuntime.cpp           |   8 +-
 clang/lib/CodeGen/CGHLSLRuntime.h             |   2 +-
 clang/lib/Sema/SemaHLSL.cpp                   | 245 ++++++++++++++++++
 .../ast-dump-comment-cbuffe-tbufferr.hlsl     |  15 +-
 clang/test/AST/HLSL/cbuffer.hlsl              | 217 ++++++++++++++++
 clang/test/AST/HLSL/cbuffer_tbuffer.hlsl      |  26 --
 clang/test/AST/HLSL/pch_hlsl_buffer.hlsl      |  17 +-
 9 files changed, 509 insertions(+), 35 deletions(-)
 create mode 100644 clang/test/AST/HLSL/cbuffer.hlsl
 delete mode 100644 clang/test/AST/HLSL/cbuffer_tbuffer.hlsl

diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h
index 9c470f09406378..0a66ed3d499ff2 100644
--- a/clang/include/clang/AST/Decl.h
+++ b/clang/include/clang/AST/Decl.h
@@ -4967,6 +4967,7 @@ class HLSLBufferDecl final : public NamedDecl, public 
DeclContext {
   SourceLocation getRBraceLoc() const { return RBraceLoc; }
   void setRBraceLoc(SourceLocation L) { RBraceLoc = L; }
   bool isCBuffer() const { return IsCBuffer; }
+  const Type *getResourceHandleType() const;
 
   // Implement isa/cast/dyncast/etc.
   static bool classof(const Decl *D) { return classofKind(D->getKind()); }
diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp
index 31749e46458d6a..a4f5d1a3a71a63 100644
--- a/clang/lib/AST/Decl.cpp
+++ b/clang/lib/AST/Decl.cpp
@@ -5693,6 +5693,19 @@ HLSLBufferDecl 
*HLSLBufferDecl::CreateDeserialized(ASTContext &C,
                                     SourceLocation(), SourceLocation());
 }
 
+const Type *HLSLBufferDecl::getResourceHandleType() const {
+  // Resource handle is the last decl in the HLSLBufferDecl.
+  // If it is not present, it probably means the buffer is empty.
+  if (VarDecl *VD = llvm::dyn_cast_or_null<VarDecl>(LastDecl)) {
+    const Type *Ty = VD->getType().getTypePtr();
+    if (Ty->isHLSLAttributedResourceType()) {
+      assert(VD->getNameAsString() == "__handle");
+      return Ty;
+    }
+  }
+  return nullptr;
+}
+
 
//===----------------------------------------------------------------------===//
 // ImportDecl Implementation
 
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp 
b/clang/lib/CodeGen/CGHLSLRuntime.cpp
index 5679bd71581795..51e20ad43fcc8d 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.cpp
+++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp
@@ -159,10 +159,12 @@ void CGHLSLRuntime::addConstant(VarDecl *D, Buffer &CB) {
   CB.Constants.emplace_back(std::make_pair(GV, LowerBound));
 }
 
-void CGHLSLRuntime::addBufferDecls(const DeclContext *DC, Buffer &CB) {
-  for (Decl *it : DC->decls()) {
+void CGHLSLRuntime::addBufferDecls(const HLSLBufferDecl *D, Buffer &CB) {
+  for (Decl *it : D->decls()) {
     if (auto *ConstDecl = dyn_cast<VarDecl>(it)) {
-      addConstant(ConstDecl, CB);
+      if (ConstDecl->getType().getTypePtr() != D->getResourceHandleType()) {
+        addConstant(ConstDecl, CB);
+      }
     } else if (isa<CXXRecordDecl, EmptyDecl>(it)) {
       // Nothing to do for this declaration.
     } else if (isa<FunctionDecl>(it)) {
diff --git a/clang/lib/CodeGen/CGHLSLRuntime.h 
b/clang/lib/CodeGen/CGHLSLRuntime.h
index 00e110e8e6fa27..870a5bd0ea6b4f 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.h
+++ b/clang/lib/CodeGen/CGHLSLRuntime.h
@@ -169,7 +169,7 @@ class CGHLSLRuntime {
                                    llvm::hlsl::ElementType ET,
                                    BufferResBinding &Binding);
   void addConstant(VarDecl *D, Buffer &CB);
-  void addBufferDecls(const DeclContext *DC, Buffer &CB);
+  void addBufferDecls(const HLSLBufferDecl *D, Buffer &CB);
   llvm::Triple::ArchType getArch();
   llvm::SmallVector<Buffer> Buffers;
 
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index 65ddee05a21512..c726672c0118e0 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -21,10 +21,12 @@
 #include "clang/AST/TypeLoc.h"
 #include "clang/Basic/Builtins.h"
 #include "clang/Basic/DiagnosticSema.h"
+#include "clang/Basic/IdentifierTable.h"
 #include "clang/Basic/LLVM.h"
 #include "clang/Basic/SourceLocation.h"
 #include "clang/Basic/TargetInfo.h"
 #include "clang/Sema/Initialization.h"
+#include "clang/Sema/Lookup.h"
 #include "clang/Sema/ParsedAttr.h"
 #include "clang/Sema/Sema.h"
 #include "clang/Sema/Template.h"
@@ -32,11 +34,13 @@
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Twine.h"
 #include "llvm/Support/Casting.h"
 #include "llvm/Support/DXILABI.h"
 #include "llvm/Support/ErrorHandling.h"
 #include "llvm/TargetParser/Triple.h"
 #include <iterator>
+#include <string>
 #include <utility>
 
 using namespace clang;
@@ -253,12 +257,253 @@ static void validatePackoffset(Sema &S, HLSLBufferDecl 
*BufDecl) {
   }
 }
 
+// Returns true if the array has a zero size = if any of the dimensions is 0
+static bool isZeroSizedArray(const ConstantArrayType *CAT) {
+  while (CAT && !CAT->isZeroSize())
+    CAT = dyn_cast<ConstantArrayType>(
+        CAT->getElementType()->getUnqualifiedDesugaredType());
+  return CAT != nullptr;
+}
+
+// Returns true if the struct can be used inside HLSL Buffer which means
+// that it does not contain intangible types, empty structs, zero-sized arrays,
+// and the same is true for its base or embedded structs.
+bool isStructHLSLBufferCompatible(const CXXRecordDecl *RD) {
+  if (RD->getTypeForDecl()->isHLSLIntangibleType() ||
+      (RD->field_empty() && RD->getNumBases() == 0))
+    return false;
+  // check fields
+  for (const FieldDecl *Field : RD->fields()) {
+    QualType Ty = Field->getType();
+    if (Ty->isRecordType()) {
+      if (!isStructHLSLBufferCompatible(Ty->getAsCXXRecordDecl()))
+        return false;
+    } else if (Ty->isConstantArrayType()) {
+      if (isZeroSizedArray(cast<ConstantArrayType>(Ty)))
+        return false;
+    }
+  }
+  // check bases
+  for (const CXXBaseSpecifier &Base : RD->bases())
+    if (!isStructHLSLBufferCompatible(Base.getType()->getAsCXXRecordDecl()))
+      return false;
+  return true;
+}
+
+static CXXRecordDecl *findRecordDecl(Sema &S, IdentifierInfo *II,
+                                     DeclContext *DC) {
+  DeclarationNameInfo NameInfo =
+      DeclarationNameInfo(DeclarationName(II), SourceLocation());
+  LookupResult R(S, NameInfo, Sema::LookupOrdinaryName);
+  S.LookupName(R, S.getScopeForContext(DC));
+  if (R.isSingleResult())
+    return R.getAsSingle<CXXRecordDecl>();
+  return nullptr;
+}
+
+// Creates a name for buffer layout struct using the provide name base.
+// If the name must be unique (not previously defined), a suffix is added
+// until a unique name is found.
+static IdentifierInfo *getHostLayoutStructName(Sema &S,
+                                               IdentifierInfo *NameBaseII,
+                                               bool MustBeUnique,
+                                               DeclContext *DC) {
+  ASTContext &AST = S.getASTContext();
+  std::string NameBase;
+  if (NameBaseII) {
+    NameBase = NameBaseII->getName().str();
+  } else {
+    // anonymous struct
+    NameBase = "anon";
+    MustBeUnique = true;
+  }
+
+  std::string Name = "__hostlayout.struct." + NameBase;
+  IdentifierInfo *II = &AST.Idents.get(Name, tok::TokenKind::identifier);
+  if (!MustBeUnique)
+    return II;
+
+  unsigned suffix = 0;
+  while (true) {
+    if (suffix != 0)
+      II = &AST.Idents.get((llvm::Twine(Name) + "." + Twine(suffix)).str(),
+                           tok::TokenKind::identifier);
+    if (!findRecordDecl(S, II, DC))
+      return II;
+    // declaration with that name already exists - increment suffix and try
+    // again until unique name is found
+    suffix++;
+  };
+}
+
+// Returns true if the record type is an HLSL resource class
+static bool isResourceRecordType(const Type *Ty) {
+  return HLSLAttributedResourceType::findHandleTypeOnResource(Ty) != nullptr;
+}
+
+static CXXRecordDecl *createHostLayoutStruct(Sema &S, CXXRecordDecl 
*StructDecl,
+                                             HLSLBufferDecl *BufDecl);
+
+// Creates a field declaration of given name and type for HLSL buffer layout
+// struct. Returns nullptr if the type cannot be use in HLSL Buffer layout.
+static FieldDecl *createFieldForHostLayoutStruct(Sema &S, const Type *Ty,
+                                                 IdentifierInfo *II,
+                                                 CXXRecordDecl *LayoutStruct,
+                                                 HLSLBufferDecl *BufDecl) {
+  if (Ty->isRecordType()) {
+    if (isResourceRecordType(Ty))
+      return nullptr;
+    CXXRecordDecl *RD = Ty->getAsCXXRecordDecl();
+    if (!isStructHLSLBufferCompatible(RD)) {
+      RD = createHostLayoutStruct(S, RD, BufDecl);
+      if (!RD)
+        return nullptr;
+      Ty = RD->getTypeForDecl();
+    }
+  } else if (Ty->isConstantArrayType()) {
+    if (isZeroSizedArray(cast<ConstantArrayType>(Ty)))
+      return nullptr;
+  }
+  QualType QT = QualType(Ty, 0);
+  ASTContext &AST = S.getASTContext();
+  TypeSourceInfo *TSI = AST.getTrivialTypeSourceInfo(QT, SourceLocation());
+  auto *Field = FieldDecl::Create(AST, LayoutStruct, SourceLocation(),
+                                  SourceLocation(), II, QT, TSI, nullptr, 
false,
+                                  InClassInitStyle::ICIS_NoInit);
+  Field->setAccess(AccessSpecifier::AS_private);
+  return Field;
+}
+
+// Creates host layout struct for a struct included in HLSL Buffer.
+// The layout struct will include only fields that are allowed in HLSL buffer.
+// These fields will be filtered out:
+// - resource classes
+// - empty structs
+// - zero-sized arrays
+// Returns nullptr if the resulting layout struct would be empty.
+static CXXRecordDecl *createHostLayoutStruct(Sema &S, CXXRecordDecl 
*StructDecl,
+                                             HLSLBufferDecl *BufDecl) {
+  assert(!isStructHLSLBufferCompatible(StructDecl) &&
+         "struct is already HLSL buffer compatible");
+
+  ASTContext &AST = S.getASTContext();
+  DeclContext *DC = StructDecl->getDeclContext();
+  IdentifierInfo *II = getHostLayoutStructName(
+      S, StructDecl->getIdentifier(), false, BufDecl->getDeclContext());
+
+  // reuse existing if the layout struct if it already exists
+  if (CXXRecordDecl *RD = findRecordDecl(S, II, DC))
+    return RD;
+
+  CXXRecordDecl *LS =
+      CXXRecordDecl::Create(AST, TagDecl::TagKind::Class, BufDecl,
+                            SourceLocation(), SourceLocation(), II);
+  LS->setImplicit(true);
+  LS->startDefinition();
+
+  // copy base struct, create HLSL Buffer compatible version if needed
+  if (unsigned NumBases = StructDecl->getNumBases()) {
+    assert(NumBases == 1 && "HLSL supports only one base type");
+    CXXBaseSpecifier Base = *StructDecl->bases_begin();
+    CXXRecordDecl *BaseDecl = Base.getType()->getAsCXXRecordDecl();
+    if (!isStructHLSLBufferCompatible(BaseDecl)) {
+      BaseDecl = createHostLayoutStruct(S, BaseDecl, BufDecl);
+      if (BaseDecl) {
+        TypeSourceInfo *TSI = AST.getTrivialTypeSourceInfo(
+            QualType(BaseDecl->getTypeForDecl(), 0));
+        Base = CXXBaseSpecifier(SourceRange(), false, StructDecl->isClass(),
+                                AS_none, TSI, SourceLocation());
+      }
+    }
+    if (BaseDecl) {
+      const CXXBaseSpecifier *BasesArray[1] = {&Base};
+      LS->setBases(BasesArray, 1);
+    }
+  }
+
+  // filter struct fields
+  for (const FieldDecl *FD : StructDecl->fields()) {
+    const Type *Ty = FD->getType()->getUnqualifiedDesugaredType();
+    if (FieldDecl *NewFD = createFieldForHostLayoutStruct(
+            S, Ty, FD->getIdentifier(), LS, BufDecl))
+      LS->addDecl(NewFD);
+  }
+  LS->completeDefinition();
+
+  if (LS->field_empty() && LS->getNumBases() == 0)
+    return nullptr;
+  BufDecl->addDecl(LS);
+  return LS;
+}
+
+// Creates host layout struct for HLSL Buffer. The struct will include only
+// fields of types that are allowed in HLSL buffer and it will filter out:
+// - static variable declarations
+// - resource classes
+// - empty structs
+// - zero-sized arrays
+// - non-variable declarations
+static CXXRecordDecl *createHostLayoutStructForBuffer(Sema &S,
+                                                      HLSLBufferDecl *BufDecl) 
{
+  ASTContext &AST = S.getASTContext();
+  IdentifierInfo *II = getHostLayoutStructName(S, BufDecl->getIdentifier(),
+                                               true, 
BufDecl->getDeclContext());
+
+  CXXRecordDecl *LS =
+      CXXRecordDecl::Create(AST, TagDecl::TagKind::Class, BufDecl,
+                            SourceLocation(), SourceLocation(), II);
+  LS->setImplicit(true);
+  LS->startDefinition();
+
+  for (const Decl *D : BufDecl->decls()) {
+    const VarDecl *VD = dyn_cast<VarDecl>(D);
+    if (!VD || VD->getStorageClass() == SC_Static)
+      continue;
+    const Type *Ty = VD->getType()->getUnqualifiedDesugaredType();
+    if (FieldDecl *FD = createFieldForHostLayoutStruct(
+            S, Ty, VD->getIdentifier(), LS, BufDecl))
+      LS->addDecl(FD);
+  }
+  LS->completeDefinition();
+  BufDecl->addDecl(LS);
+  return LS;
+}
+
+// Creates a "__handle" declaration for the HLSL Buffer type
+// with the corresponding HLSL resource type and adds it to the HLSLBufferDecl
+static void createHLSLBufferHandle(Sema &S, HLSLBufferDecl *BufDecl,
+                                   CXXRecordDecl *LayoutStruct) {
+  ASTContext &AST = S.getASTContext();
+
+  HLSLAttributedResourceType::Attributes ResAttrs(
+      BufDecl->isCBuffer() ? ResourceClass::CBuffer : ResourceClass::SRV, 
false,
+      false);
+  QualType ResHandleTy = AST.getHLSLAttributedResourceType(
+      AST.HLSLResourceTy, QualType(LayoutStruct->getTypeForDecl(), 0),
+      ResAttrs);
+
+  IdentifierInfo *II = &AST.Idents.get("__handle", tok::TokenKind::identifier);
+  VarDecl *VD = VarDecl::Create(
+      BufDecl->getASTContext(), BufDecl, SourceLocation(), SourceLocation(), 
II,
+      ResHandleTy, AST.getTrivialTypeSourceInfo(ResHandleTy, SourceLocation()),
+      SC_None);
+  BufDecl->addDecl(VD);
+}
+
+// Handle end of cbuffer/tbuffer declaration
 void SemaHLSL::ActOnFinishBuffer(Decl *Dcl, SourceLocation RBrace) {
   auto *BufDecl = cast<HLSLBufferDecl>(Dcl);
   BufDecl->setRBraceLoc(RBrace);
 
   validatePackoffset(SemaRef, BufDecl);
 
+  // create buffer layout struct
+  CXXRecordDecl *LayoutStruct =
+      createHostLayoutStructForBuffer(SemaRef, BufDecl);
+
+  // create buffer resource handle
+  createHLSLBufferHandle(SemaRef, BufDecl, LayoutStruct);
+
   SemaRef.PopDeclContext();
 }
 
diff --git a/clang/test/AST/HLSL/ast-dump-comment-cbuffe-tbufferr.hlsl 
b/clang/test/AST/HLSL/ast-dump-comment-cbuffe-tbufferr.hlsl
index e6a2ea7c6d2dc6..5956eef27205d5 100644
--- a/clang/test/AST/HLSL/ast-dump-comment-cbuffe-tbufferr.hlsl
+++ b/clang/test/AST/HLSL/ast-dump-comment-cbuffe-tbufferr.hlsl
@@ -44,7 +44,13 @@ tbuffer B {
 // AST-NEXT:`-ParagraphComment {{.*}}<col:4, col:17>
 // AST-NEXT:`-TextComment {{.*}}<col:4, col:17> Text=" CBuffer decl."
 // AST-NEXT:-VarDecl {{.*}}<line:15:5, col:11> col:11 a 'float'
-// AST-NEXT:`-VarDecl {{.*}}<line:19:5, col:9> col:9 b 'int'
+// AST-NEXT:-VarDecl {{.*}}<line:19:5, col:9> col:9 b 'int'
+// AST-NEXT:CXXRecordDecl 0x[[CB:[0-9a-f]+]] {{.*}} implicit class 
__hostlayout.struct.A definition
+// AST:FieldDecl 0x[[CB:[0-9a-f]+]] {{.*}} a 'float'
+// AST-NEXT:FieldDecl 0x[[CB:[0-9a-f]+]] {{.*}} b 'int'
+// AST-NEXT:VarDecl 0x[[CB:[0-9a-f]+]] {{.*}} __handle '__hlsl_resource_t 
+// AST-SAME{LITERAL}: [[hlsl::resource_class(CBuffer)]] 
[[hlsl::contained_type(__hostlayout.struct.A)]]'
+
 // AST-NEXT:HLSLBufferDecl {{.*}}<line:29:1, line:38:1> line:29:9 tbuffer B
 // AST-NEXT:-HLSLResourceClassAttr {{.*}} <<invalid sloc>> Implicit SRV
 // AST-NEXT:-HLSLResourceAttr {{.*}} <<invalid sloc>> Implicit TBuffer
@@ -52,4 +58,9 @@ tbuffer B {
 // AST-NEXT: `-ParagraphComment {{.*}}<col:4, col:17>
 // AST-NEXT:  `-TextComment {{.*}}<col:4, col:17> Text=" TBuffer decl."
 // AST-NEXT:-VarDecl {{.*}}<line:33:5, col:11> col:11 c 'float'
-// AST-NEXT:`-VarDecl {{.*}} <line:37:5, col:9> col:9 d 'int'
+// AST-NEXT:-VarDecl {{.*}} <line:37:5, col:9> col:9 d 'int'
+// AST-NEXT:CXXRecordDecl 0x[[CB:[0-9a-f]+]] {{.*}} implicit class 
__hostlayout.struct.B definition
+// AST:FieldDecl 0x[[CB:[0-9a-f]+]] {{.*}} c 'float'
+// AST-NEXT:FieldDecl 0x[[CB:[0-9a-f]+]] {{.*}} d 'int'
+// AST-NEXT:VarDecl 0x[[CB:[0-9a-f]+]] {{.*}} __handle '__hlsl_resource_t
+// AST-SAME{LITERAL}: [[hlsl::resource_class(SRV)]] 
[[hlsl::contained_type(__hostlayout.struct.B)]]'
diff --git a/clang/test/AST/HLSL/cbuffer.hlsl b/clang/test/AST/HLSL/cbuffer.hlsl
new file mode 100644
index 00000000000000..b47ea930c1b57f
--- /dev/null
+++ b/clang/test/AST/HLSL/cbuffer.hlsl
@@ -0,0 +1,217 @@
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -ast-dump -o - %s | 
FileCheck %s
+
+struct EmptyStruct {
+};
+
+struct A {
+  float a;
+};
+
+struct B {
+  RWBuffer<float> buf;
+  EmptyStruct es;
+  float ea[0];
+  float a;
+};
+
+struct C {
+  EmptyStruct es;
+};
+
+typedef B BTypedef;
+typedef C CTypedef;
+
+struct D : B {
+  float b;
+};
+
+struct E : EmptyStruct {
+  float c;
+};
+
+struct F : A {
+  int ae[0];
+};
+
+typedef float EmptyArrayTypedef[10][0];
+
+// CHECK: HLSLBufferDecl {{.*}} line:41:9 cbuffer CB
+// CHECK: HLSLResourceClassAttr {{.*}} Implicit CBuffer
+// CHECK: HLSLResourceAttr {{.*}} Implicit CBuffer
+cbuffer CB {
+  // CHECK: VarDecl {{.*}} col:9 used a1 'float'
+  float a1;
+
+  // CHECK: CXXRecordDecl {{.*}} implicit class __hostlayout.struct.CB 
definition
+  // CHECK: FieldDecl {{.*}} a1 'float'
+  // CHECK: VarDecl {{.*}} __handle '__hlsl_resource_t
+  // CHECK-SAME{LITERAL}: [[hlsl::resource_class(CBuffer)]] 
[[hlsl::contained_type(__hostlayout.struct.CB)]]'
+}
+
+// Check that buffer layout struct does not include resources or empty types 
+// CHECK: HLSLBufferDecl {{.*}} line:55:9 cbuffer CB
+// CHECK: HLSLResourceClassAttr {{.*}} Implicit CBuffer
+// CHECK: HLSLResourceAttr {{.*}} Implicit CBuffer
+cbuffer CB {
+  // CHECK: VarDecl {{.*}} col:9 used a2 'float'
+  float a2;
+  // CHECK: VarDecl {{.*}} col:19 b2 'RWBuffer<float>':'hlsl::RWBuffer<float>'
+  RWBuffer<float> b2; 
+  // CHECK: VarDecl {{.*}} col:15 c2 'EmptyStruct'
+  EmptyStruct c2;
+  // CHECK: VarDecl {{.*}} col:9 d2 'float[0]'
+  float d2[0];
+  // CHECK: VarDecl {{.*}} col:9 e2 'float'
+  float e2;
+
+  // CHECK: CXXRecordDecl {{.*}} implicit class __hostlayout.struct.CB.1 
definition
+  // CHECK: FieldDecl {{.*}} a2 'float'
+  // CHECK-NEXT: FieldDecl {{.*}} e2 'float'
+  // CHECK: VarDecl {{.*}} __handle '__hlsl_resource_t
+  // CHECK-SAME{LITERAL}: [[hlsl::resource_class(CBuffer)]] 
[[hlsl::contained_type(__hostlayout.struct.CB.1)]]'
+}
+
+// Check that layout struct is created for B and the empty struct C is removed
+// CHECK: HLSLBufferDecl {{.*}} line:78:9 cbuffer CB
+// CHECK: HLSLResourceClassAttr {{.*}} Implicit CBuffer
+// CHECK: HLSLResourceAttr {{.*}} Implicit CBuffer
+cbuffer CB {
+  // CHECK: VarDecl {{.*}} col:5 used s1 'A'
+  A s1;
+  // CHECK: VarDecl {{.*}} col:5 s2 'B'
+  B s2;
+  // CHECK: VarDecl {{.*}} col:12 s3 'CTypedef':'C
+  CTypedef s3;
+
+  // CHECK: CXXRecordDecl {{.*}} implicit class __hostlayout.struct.B 
definition
+  // CHECK: FieldDecl {{.*}} a 'float'
+
+  // CHECK: CXXRecordDecl {{.*}} implicit class __hostlayout.struct.CB.2 
definition
+  // CHECK: FieldDecl {{.*}} s1 'A'
+  // CHECK: FieldDecl {{.*}} s2 '__hostlayout.struct.B'
+  // CHECK-NEXT: VarDecl {{.*}} __handle '__hlsl_resource_t
+  // CHECK-SAME{LITERAL}: [[hlsl::resource_class(CBuffer)]] 
[[hlsl::contained_type(__hostlayout.struct.CB.2)]]'
+}
+
+// check that layout struct is created for D because of its base struct
+// CHECK: HLSLBufferDecl {{.*}} line:100:9 cbuffer CB
+// CHECK: HLSLResourceClassAttr {{.*}} Implicit CBuffer
+// CHECK: HLSLResourceAttr {{.*}} Implicit CBuffer
+cbuffer CB {
+  // CHECK: VarDecl {{.*}} s4 'D'
+  D s4;
+
+  // CHECK: CXXRecordDecl {{.*}} implicit class __hostlayout.struct.D 
definition
+  // CHECK: FieldDecl {{.*}} b 'float'
+
+  // CHECK: CXXRecordDecl {{.*}} implicit class __hostlayout.struct.CB.3 
definition
+  // CHECK: FieldDecl {{.*}} s4 '__hostlayout.struct.D'
+  // CHECK: VarDecl {{.*}} __handle '__hlsl_resource_t
+  // CHECK-SAME{LITERAL}: [[hlsl::resource_class(CBuffer)]] 
[[hlsl::contained_type(__hostlayout.struct.CB.3)]]'
+}
+
+// check that layout struct is created for E because because its base struct
+// is empty and should be eliminated, and BTypedef should reuse the previously
+// defined '__hostlayout.struct.B' 
+// CHECK: HLSLBufferDecl {{.*}} line:119:9 cbuffer CB
+// CHECK: HLSLResourceClassAttr {{.*}} Implicit CBuffer
+// CHECK: HLSLResourceAttr {{.*}} Implicit CBuffer
+cbuffer CB {
+  // CHECK: VarDecl {{.*}}  s5 'E'
+  E s5;
+  // CHECK: VarDecl {{.*}} s6 'BTypedef':'B'
+  BTypedef s6;
+
+  // CHECK: CXXRecordDecl {{.*}} implicit class __hostlayout.struct.E 
definition
+  // CHECK: FieldDecl {{.*}} c 'float'
+
+  // CHECK-NOT: CXXRecordDecl {{.*}} implicit class __hostlayout.struct.B 
definition
+
+  // CHECK: CXXRecordDecl {{.*}}  implicit class __hostlayout.struct.CB.4 
definition
+  // CHECK: FieldDecl {{.*}} s5 '__hostlayout.struct.E'
+  // CHECK: FieldDecl {{.*}} s6 '__hostlayout.struct.B'
+  // CHECK: VarDecl {{.*}} __handle '__hlsl_resource_t
+  // CHECK-SAME{LITERAL}: [[hlsl::resource_class(CBuffer)]] 
[[hlsl::contained_type(__hostlayout.struct.CB.4)]]'
+}
+
+// check that this produces empty layout struct
+// CHECK: HLSLBufferDecl {{.*}} line:141:9 cbuffer CB
+// CHECK: HLSLResourceClassAttr {{.*}} Implicit CBuffer
+// CHECK: HLSLResourceAttr {{.*}} Implicit CBuffer
+cbuffer CB {
+  // CHECK: FunctionDecl {{.*}} f 'void ()'
+  void f() {}
+  // CHECK: VarDecl {{.*}} SV 'float' static
+  static float SV;
+  // CHECK: VarDecl {{.*}} s7 'EmptyStruct' callinit
+  EmptyStruct s7;
+  // CHECK: VarDecl {{.*}} Buf 'RWBuffer<float>':'hlsl::RWBuffer<float>' 
callinit
+  RWBuffer<float> Buf;
+  // CHECK: VarDecl {{.*}} ea 'EmptyArrayTypedef':'float[10][0]'
+  EmptyArrayTypedef ea;
+
+  // CHECK: CXXRecordDecl {{.*}} implicit class __hostlayout.struct.CB.5 
definition
+  // CHECK-NOT: FieldDecl
+  // CHECK: VarDecl {{.*}} __handle '__hlsl_resource_t
+  // CHECK-SAME{LITERAL}: [[hlsl::resource_class(CBuffer)]] 
[[hlsl::contained_type(__hostlayout.struct.CB.5)]]'
+}
+
+// check host layout struct with compatible base struct
+// CHECK: HLSLBufferDecl {{.*}} line:163:9 cbuffer CB
+// CHECK: HLSLResourceClassAttr {{.*}} Implicit CBuffer
+// CHECK: HLSLResourceAttr {{.*}} Implicit CBuffer
+cbuffer CB {
+  // CHECK: VarDecl {{.*}} s8 'F'
+  F s8;
+
+  // CHECK: CXXRecordDecl {{.*}} implicit class __hostlayout.struct.F 
definition
+  // CHECK: public 'A'
+
+  // CHECK: CXXRecordDecl {{.*}} implicit class __hostlayout.struct.CB.6 
definition
+  // CHECK: FieldDecl {{.*}} s8 '__hostlayout.struct.F'
+  // CHECK: VarDecl  {{.*}} __handle '__hlsl_resource_t
+  // CHECK-SAME{LITERAL}: [[hlsl::resource_class(CBuffer)]] 
[[hlsl::contained_type(__hostlayout.struct.CB.6)]]'
+}
+
+// anonymous structs
+// CHECK: HLSLBufferDecl {{.*}} line:180:9 cbuffer CB
+// CHECK: HLSLResourceClassAttr {{.*}} Implicit CBuffer
+// CHECK: HLSLResourceAttr {{.*}} Implicit CBuffer
+cbuffer CB {
+  // CHECK: CXXRecordDecl {{.*}} struct definition
+  struct {
+    // CHECK: FieldDecl {{.*}} e 'float'
+    float e;
+    // CHECK: FieldDecl {{.*}} c 'int[0][1]'
+    int c[0][1];
+    // CHECK: FieldDecl {{.*}} f 'RWBuffer<float>':'hlsl::RWBuffer<float>'
+    RWBuffer<float> f;
+  } s9;
+  // CHECK: VarDecl {{.*}} s9 'struct (unnamed struct at 
{{.*}}cbuffer.hlsl:182:3
+  
+  // CHECK: CXXRecordDecl {{.*}} struct definition
+  struct {
+    // CHECK: FieldDecl {{.*}} g 'int'
+    int g;
+    // CHECK: FieldDecl {{.*}} f 'RWBuffer<float>':'hlsl::RWBuffer<float>'
+    RWBuffer<float> f;
+  } s10;
+  // CHECK: VarDecl {{.*}} s10 'struct (unnamed struct at 
{{.*}}cbuffer.hlsl:193:3
+
+  // CHECK: CXXRecordDecl {{.*}} implicit class __hostlayout.struct.anon 
definition
+  // CHECK: FieldDecl {{.*}} e 'float'
+
+  // CHECK: CXXRecordDecl {{.*}} implicit class __hostlayout.struct.anon.1 
definition
+  // CHECK: FieldDecl {{.*}} g 'int'
+
+  // CHECK: CXXRecordDecl {{.*}} implicit class __hostlayout.struct.CB.7 
definition
+  // CHECK: FieldDecl {{.*}} s9 '__hostlayout.struct.anon'
+  // CHECK: FieldDecl {{.*}} s10 '__hostlayout.struct.anon.1'
+  // CHECK-NEXT: VarDecl {{.*}} __handle '__hlsl_resource_t
+  // CHECK-SAME{LITERAL} [[hlsl::resource_class(CBuffer)]] 
[[hlsl::contained_type(__hostlayout.struct.CB.7)]]'
+}
+
+// Add uses for the constant buffer declarations so they are not optimized 
awayexport 
+export float foo() {
+  return a1 + a2 + s1.a + s4.b + s5.c + s8.a + s9.e;
+}
diff --git a/clang/test/AST/HLSL/cbuffer_tbuffer.hlsl 
b/clang/test/AST/HLSL/cbuffer_tbuffer.hlsl
deleted file mode 100644
index 5e558354cd3a03..00000000000000
--- a/clang/test/AST/HLSL/cbuffer_tbuffer.hlsl
+++ /dev/null
@@ -1,26 +0,0 @@
-// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -x hlsl -ast-dump -o 
- %s | FileCheck %s
-
-// CHECK:HLSLBufferDecl 0x[[CB:[0-9a-f]+]] {{.*}} line:7:9 cbuffer CB
-// CHECK:HLSLResourceClassAttr 0x{{[0-9a-f]+}} <<invalid sloc>> Implicit 
CBuffer
-// CHECK-NEXT:HLSLResourceAttr {{.*}} <<invalid sloc>> Implicit CBuffer
-// CHECK-NEXT:VarDecl 0x[[A:[0-9a-f]+]] {{.*}} col:9 used a 'float'
-cbuffer CB {
-  float a;
-}
-
-// CHECK:HLSLBufferDecl 0x[[TB:[0-9a-f]+]] {{.*}} line:15:9 tbuffer TB
-// CHECK:HLSLResourceClassAttr 0x{{[0-9a-f]+}} <<invalid sloc>> Implicit SRV
-// CHECK-NEXT:HLSLResourceAttr {{.*}} <<invalid sloc>> Implicit TBuffer
-// CHECK-NEXT:VarDecl 0x[[B:[0-9a-f]+]] {{.*}} col:9 used b 'float'
-tbuffer TB {
-  float b;
-}
-
-float foo() {
-// CHECK: BinaryOperator 0x{{[0-9a-f]+}} <col:10, col:14> 'float' '+'
-// CHECK-NEXT: ImplicitCastExpr 0x{{[0-9a-f]+}} <col:10> 'float' 
<LValueToRValue>
-// CHECK-NEXT: DeclRefExpr 0x{{[0-9a-f]+}} <col:10> 'float' lvalue Var 0x[[A]] 
'a' 'float'
-// CHECK-NEXT: ImplicitCastExpr 0x{{[0-9a-f]+}} <col:14> 'float' 
<LValueToRValue>
-// CHECK-NEXT: DeclRefExpr 0x{{[0-9a-f]+}} <col:14> 'float' lvalue Var 0x[[B]] 
'b' 'float'
-  return a + b;
-}
diff --git a/clang/test/AST/HLSL/pch_hlsl_buffer.hlsl 
b/clang/test/AST/HLSL/pch_hlsl_buffer.hlsl
index 281d8be8addf09..9e8ab95acf8178 100644
--- a/clang/test/AST/HLSL/pch_hlsl_buffer.hlsl
+++ b/clang/test/AST/HLSL/pch_hlsl_buffer.hlsl
@@ -15,15 +15,26 @@ tbuffer B {
 float foo() {
   return a + b;
 }
+
 // Make sure cbuffer/tbuffer works for PCH.
 // CHECK:HLSLBufferDecl 0x{{[0-9a-f]+}} <{{.*}}:7:1, line:9:1> line:7:9 
imported <undeserialized declarations> cbuffer A
 // CHECK-NEXT:HLSLResourceClassAttr {{.*}} <<invalid sloc>> Implicit CBuffer
 // CHECK-NEXT:HLSLResourceAttr {{.*}} <<invalid sloc>> Implicit CBuffer
-// CHECK-NEXT:`-VarDecl 0x[[A:[0-9a-f]+]] <line:8:3, col:9> col:9 imported 
used a 'float'
-// CHECK-NEXT:HLSLBufferDecl 0x{{[0-9a-f]+}} <line:11:1, line:13:1> line:11:9 
imported <undeserialized declarations> tbuffer B
+// CHECK-NEXT:VarDecl 0x[[A:[0-9a-f]+]] <line:8:3, col:9> col:9 imported used 
a 'float'
+// CHECK-NEXT:CXXRecordDecl 0x{{[0-9a-f]+}} {{.*}} imported implicit 
<undeserialized declarations> class __hostlayout.struct.A definition
+// CHECK:FieldDecl 0x{{[0-9a-f]+}} {{.*}} imported a 'float'
+// CHECK-NEXT:VarDecl 0x{{[0-9a-f]+}} {{.*}} imported __handle 
'__hlsl_resource_t
+// CHECK-SAME{LITERAL}: [[hlsl::resource_class(CBuffer)]] 
[[hlsl::contained_type(__hostlayout.struct.A)]]'
+
+// CHECK:HLSLBufferDecl 0x{{[0-9a-f]+}} <line:11:1, line:13:1> line:11:9 
imported <undeserialized declarations> tbuffer B
 // CHECK-NEXT:HLSLResourceClassAttr {{.*}} <<invalid sloc>> Implicit SRV
 // CHECK-NEXT:HLSLResourceAttr {{.*}} <<invalid sloc>> Implicit TBuffer
-// CHECK-NEXT:`-VarDecl 0x[[B:[0-9a-f]+]] <line:12:3, col:9> col:9 imported 
used b 'float'
+// CHECK-NEXT:VarDecl 0x[[B:[0-9a-f]+]] <line:12:3, col:9> col:9 imported used 
b 'float'
+// CHECK-NEXT:CXXRecordDecl 0x{{[0-9a-f]+}} {{.*}} imported implicit 
<undeserialized declarations> class __hostlayout.struct.B definition
+// CHECK:FieldDecl 0x{{[0-9a-f]+}} {{.*}} imported b 'float'
+// CHECK-NEXT:VarDecl 0x{{[0-9a-f]+}} {{.*}} imported __handle 
'__hlsl_resource_t
+// CHECK-SAME{LITERAL}: [[hlsl::resource_class(SRV)]] 
[[hlsl::contained_type(__hostlayout.struct.B)]]'
+
 // CHECK-NEXT:FunctionDecl 0x{{[0-9a-f]+}} <line:15:1, line:17:1> line:15:7 
imported foo 'float ()'
 // CHECK-NEXT:CompoundStmt 0x{{[0-9a-f]+}} <col:13, line:17:1>
 // CHECK-NEXT:ReturnStmt 0x{{[0-9a-f]+}} <line:16:3, col:14>

>From 07ec28399bbef342ff782000cd2cdd64a2ccf082 Mon Sep 17 00:00:00 2001
From: Helena Kotas <heko...@microsoft.com>
Date: Tue, 14 Jan 2025 12:30:27 -0800
Subject: [PATCH 2/8] Remove resource handle from HLSLBufDecl, cleanup tests

---
 clang/include/clang/AST/Decl.h                |  1 -
 clang/lib/AST/Decl.cpp                        | 13 ----
 clang/lib/CodeGen/CGHLSLRuntime.cpp           |  8 +--
 clang/lib/CodeGen/CGHLSLRuntime.h             |  2 +-
 clang/lib/Sema/SemaHLSL.cpp                   | 24 -------
 .../ast-dump-comment-cbuffe-tbufferr.hlsl     | 66 -------------------
 .../ast-dump-comment-cbuffer-tbuffer.hlsl     | 62 +++++++++++++++++
 clang/test/AST/HLSL/cbuffer.hlsl              | 52 +++------------
 clang/test/AST/HLSL/pch_hlsl_buffer.hlsl      | 44 ++++++-------
 9 files changed, 96 insertions(+), 176 deletions(-)
 delete mode 100644 clang/test/AST/HLSL/ast-dump-comment-cbuffe-tbufferr.hlsl
 create mode 100644 clang/test/AST/HLSL/ast-dump-comment-cbuffer-tbuffer.hlsl

diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h
index 0a66ed3d499ff2..9c470f09406378 100644
--- a/clang/include/clang/AST/Decl.h
+++ b/clang/include/clang/AST/Decl.h
@@ -4967,7 +4967,6 @@ class HLSLBufferDecl final : public NamedDecl, public 
DeclContext {
   SourceLocation getRBraceLoc() const { return RBraceLoc; }
   void setRBraceLoc(SourceLocation L) { RBraceLoc = L; }
   bool isCBuffer() const { return IsCBuffer; }
-  const Type *getResourceHandleType() const;
 
   // Implement isa/cast/dyncast/etc.
   static bool classof(const Decl *D) { return classofKind(D->getKind()); }
diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp
index a4f5d1a3a71a63..31749e46458d6a 100644
--- a/clang/lib/AST/Decl.cpp
+++ b/clang/lib/AST/Decl.cpp
@@ -5693,19 +5693,6 @@ HLSLBufferDecl 
*HLSLBufferDecl::CreateDeserialized(ASTContext &C,
                                     SourceLocation(), SourceLocation());
 }
 
-const Type *HLSLBufferDecl::getResourceHandleType() const {
-  // Resource handle is the last decl in the HLSLBufferDecl.
-  // If it is not present, it probably means the buffer is empty.
-  if (VarDecl *VD = llvm::dyn_cast_or_null<VarDecl>(LastDecl)) {
-    const Type *Ty = VD->getType().getTypePtr();
-    if (Ty->isHLSLAttributedResourceType()) {
-      assert(VD->getNameAsString() == "__handle");
-      return Ty;
-    }
-  }
-  return nullptr;
-}
-
 
//===----------------------------------------------------------------------===//
 // ImportDecl Implementation
 
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp 
b/clang/lib/CodeGen/CGHLSLRuntime.cpp
index 51e20ad43fcc8d..5679bd71581795 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.cpp
+++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp
@@ -159,12 +159,10 @@ void CGHLSLRuntime::addConstant(VarDecl *D, Buffer &CB) {
   CB.Constants.emplace_back(std::make_pair(GV, LowerBound));
 }
 
-void CGHLSLRuntime::addBufferDecls(const HLSLBufferDecl *D, Buffer &CB) {
-  for (Decl *it : D->decls()) {
+void CGHLSLRuntime::addBufferDecls(const DeclContext *DC, Buffer &CB) {
+  for (Decl *it : DC->decls()) {
     if (auto *ConstDecl = dyn_cast<VarDecl>(it)) {
-      if (ConstDecl->getType().getTypePtr() != D->getResourceHandleType()) {
-        addConstant(ConstDecl, CB);
-      }
+      addConstant(ConstDecl, CB);
     } else if (isa<CXXRecordDecl, EmptyDecl>(it)) {
       // Nothing to do for this declaration.
     } else if (isa<FunctionDecl>(it)) {
diff --git a/clang/lib/CodeGen/CGHLSLRuntime.h 
b/clang/lib/CodeGen/CGHLSLRuntime.h
index 870a5bd0ea6b4f..7858abb9e51e96 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.h
+++ b/clang/lib/CodeGen/CGHLSLRuntime.h
@@ -169,7 +169,7 @@ class CGHLSLRuntime {
                                    llvm::hlsl::ElementType ET,
                                    BufferResBinding &Binding);
   void addConstant(VarDecl *D, Buffer &CB);
-  void addBufferDecls(const HLSLBufferDecl *D, Buffer &CB);
+  void addBufferDecls(const DeclContext *D, Buffer &CB);
   llvm::Triple::ArchType getArch();
   llvm::SmallVector<Buffer> Buffers;
 
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index c726672c0118e0..84b69e0db4c2b9 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -469,27 +469,6 @@ static CXXRecordDecl *createHostLayoutStructForBuffer(Sema 
&S,
   return LS;
 }
 
-// Creates a "__handle" declaration for the HLSL Buffer type
-// with the corresponding HLSL resource type and adds it to the HLSLBufferDecl
-static void createHLSLBufferHandle(Sema &S, HLSLBufferDecl *BufDecl,
-                                   CXXRecordDecl *LayoutStruct) {
-  ASTContext &AST = S.getASTContext();
-
-  HLSLAttributedResourceType::Attributes ResAttrs(
-      BufDecl->isCBuffer() ? ResourceClass::CBuffer : ResourceClass::SRV, 
false,
-      false);
-  QualType ResHandleTy = AST.getHLSLAttributedResourceType(
-      AST.HLSLResourceTy, QualType(LayoutStruct->getTypeForDecl(), 0),
-      ResAttrs);
-
-  IdentifierInfo *II = &AST.Idents.get("__handle", tok::TokenKind::identifier);
-  VarDecl *VD = VarDecl::Create(
-      BufDecl->getASTContext(), BufDecl, SourceLocation(), SourceLocation(), 
II,
-      ResHandleTy, AST.getTrivialTypeSourceInfo(ResHandleTy, SourceLocation()),
-      SC_None);
-  BufDecl->addDecl(VD);
-}
-
 // Handle end of cbuffer/tbuffer declaration
 void SemaHLSL::ActOnFinishBuffer(Decl *Dcl, SourceLocation RBrace) {
   auto *BufDecl = cast<HLSLBufferDecl>(Dcl);
@@ -501,9 +480,6 @@ void SemaHLSL::ActOnFinishBuffer(Decl *Dcl, SourceLocation 
RBrace) {
   CXXRecordDecl *LayoutStruct =
       createHostLayoutStructForBuffer(SemaRef, BufDecl);
 
-  // create buffer resource handle
-  createHLSLBufferHandle(SemaRef, BufDecl, LayoutStruct);
-
   SemaRef.PopDeclContext();
 }
 
diff --git a/clang/test/AST/HLSL/ast-dump-comment-cbuffe-tbufferr.hlsl 
b/clang/test/AST/HLSL/ast-dump-comment-cbuffe-tbufferr.hlsl
deleted file mode 100644
index 5956eef27205d5..00000000000000
--- a/clang/test/AST/HLSL/ast-dump-comment-cbuffe-tbufferr.hlsl
+++ /dev/null
@@ -1,66 +0,0 @@
-// RUN: %clang_cc1 -Wdocumentation -ast-dump=json -x hlsl -triple 
dxil-pc-shadermodel6.3-library %s | FileCheck %s --check-prefix=JSON
-// RUN: %clang_cc1 -Wdocumentation -ast-dump -x hlsl -triple 
dxil-pc-shadermodel6.3-library %s | FileCheck %s --check-prefix=AST
-
-// JSON:"kind": "HLSLBufferDecl",
-// JSON:"name": "A",
-// JSON-NEXT:"bufferKind": "cbuffer",
-// JSON:"kind": "TextComment",
-// JSON:"text": " CBuffer decl."
-
-/// CBuffer decl.
-cbuffer A {
-    // JSON: "kind": "VarDecl",
-    // JSON: "name": "a",
-    // JSON: "qualType": "float"
-    float a;
-    // JSON: "kind": "VarDecl",
-    // JSON: "name": "b",
-    // JSON: "qualType": "int"
-    int b;
-}
-
-// JSON:"kind": "HLSLBufferDecl",
-// JSON:"name": "B",
-// JSON-NEXT:"bufferKind": "tbuffer",
-// JSON:"kind": "TextComment",
-// JSON:"text": " TBuffer decl."
-
-/// TBuffer decl.
-tbuffer B {
-    // JSON: "kind": "VarDecl",
-    // JSON: "name": "c",
-    // JSON: "qualType": "float"
-    float c;
-    // JSON: "kind": "VarDecl",
-    // JSON: "name": "d",
-    // JSON: "qualType": "int"
-    int d;
-}
-
-// AST:HLSLBufferDecl {{.*}}:11:1, line:20:1> line:11:9 cbuffer A
-// AST-NEXT:-HLSLResourceClassAttr {{.*}} <<invalid sloc>> Implicit CBuffer
-// AST-NEXT:-HLSLResourceAttr {{.*}} <<invalid sloc>> Implicit CBuffer
-// AST-NEXT:FullComment {{.*}}<line:10:4, col:17>
-// AST-NEXT:`-ParagraphComment {{.*}}<col:4, col:17>
-// AST-NEXT:`-TextComment {{.*}}<col:4, col:17> Text=" CBuffer decl."
-// AST-NEXT:-VarDecl {{.*}}<line:15:5, col:11> col:11 a 'float'
-// AST-NEXT:-VarDecl {{.*}}<line:19:5, col:9> col:9 b 'int'
-// AST-NEXT:CXXRecordDecl 0x[[CB:[0-9a-f]+]] {{.*}} implicit class 
__hostlayout.struct.A definition
-// AST:FieldDecl 0x[[CB:[0-9a-f]+]] {{.*}} a 'float'
-// AST-NEXT:FieldDecl 0x[[CB:[0-9a-f]+]] {{.*}} b 'int'
-// AST-NEXT:VarDecl 0x[[CB:[0-9a-f]+]] {{.*}} __handle '__hlsl_resource_t 
-// AST-SAME{LITERAL}: [[hlsl::resource_class(CBuffer)]] 
[[hlsl::contained_type(__hostlayout.struct.A)]]'
-
-// AST-NEXT:HLSLBufferDecl {{.*}}<line:29:1, line:38:1> line:29:9 tbuffer B
-// AST-NEXT:-HLSLResourceClassAttr {{.*}} <<invalid sloc>> Implicit SRV
-// AST-NEXT:-HLSLResourceAttr {{.*}} <<invalid sloc>> Implicit TBuffer
-// AST-NEXT:-FullComment {{.*}}<line:28:4, col:17>
-// AST-NEXT: `-ParagraphComment {{.*}}<col:4, col:17>
-// AST-NEXT:  `-TextComment {{.*}}<col:4, col:17> Text=" TBuffer decl."
-// AST-NEXT:-VarDecl {{.*}}<line:33:5, col:11> col:11 c 'float'
-// AST-NEXT:-VarDecl {{.*}} <line:37:5, col:9> col:9 d 'int'
-// AST-NEXT:CXXRecordDecl 0x[[CB:[0-9a-f]+]] {{.*}} implicit class 
__hostlayout.struct.B definition
-// AST:FieldDecl 0x[[CB:[0-9a-f]+]] {{.*}} c 'float'
-// AST-NEXT:FieldDecl 0x[[CB:[0-9a-f]+]] {{.*}} d 'int'
-// AST-NEXT:VarDecl 0x[[CB:[0-9a-f]+]] {{.*}} __handle '__hlsl_resource_t
-// AST-SAME{LITERAL}: [[hlsl::resource_class(SRV)]] 
[[hlsl::contained_type(__hostlayout.struct.B)]]'
diff --git a/clang/test/AST/HLSL/ast-dump-comment-cbuffer-tbuffer.hlsl 
b/clang/test/AST/HLSL/ast-dump-comment-cbuffer-tbuffer.hlsl
new file mode 100644
index 00000000000000..f18ae022a1dd6a
--- /dev/null
+++ b/clang/test/AST/HLSL/ast-dump-comment-cbuffer-tbuffer.hlsl
@@ -0,0 +1,62 @@
+// RUN: %clang_cc1 -Wdocumentation -ast-dump=json -x hlsl -triple 
dxil-pc-shadermodel6.3-library %s | FileCheck %s --check-prefix=JSON
+// RUN: %clang_cc1 -Wdocumentation -ast-dump -x hlsl -triple 
dxil-pc-shadermodel6.3-library %s | FileCheck %s --check-prefix=AST
+
+// JSON:"kind": "HLSLBufferDecl",
+// JSON:"name": "A",
+// JSON-NEXT:"bufferKind": "cbuffer",
+// JSON:"kind": "TextComment",
+// JSON:"text": " CBuffer decl."
+
+/// CBuffer decl.
+cbuffer A {
+    // JSON: "kind": "VarDecl",
+    // JSON: "name": "a",
+    // JSON: "qualType": "float"
+    float a;
+    // JSON: "kind": "VarDecl",
+    // JSON: "name": "b",
+    // JSON: "qualType": "int"
+    int b;
+}
+
+// JSON:"kind": "HLSLBufferDecl",
+// JSON:"name": "B",
+// JSON-NEXT:"bufferKind": "tbuffer",
+// JSON:"kind": "TextComment",
+// JSON:"text": " TBuffer decl."
+
+/// TBuffer decl.
+tbuffer B {
+    // JSON: "kind": "VarDecl",
+    // JSON: "name": "c",
+    // JSON: "qualType": "float"
+    float c;
+    // JSON: "kind": "VarDecl",
+    // JSON: "name": "d",
+    // JSON: "qualType": "int"
+    int d;
+}
+
+// AST: HLSLBufferDecl {{.*}} line:11:9 cbuffer A
+// AST-NEXT: HLSLResourceClassAttr {{.*}} Implicit CBuffer
+// AST-NEXT: HLSLResourceAttr {{.*}} Implicit CBuffer
+// AST-NEXT: FullComment
+// AST-NEXT: ParagraphComment
+// AST-NEXT: TextComment {{.*}} Text=" CBuffer decl."
+// AST-NEXT: VarDecl {{.*}} a 'float'
+// AST-NEXT: VarDecl {{.*}} b 'int'
+// AST-NEXT: CXXRecordDecl {{.*}} implicit class __hostlayout.struct.A 
definition
+// AST: FieldDecl {{.*}} a 'float'
+// AST-NEXT: FieldDecl {{.*}} b 'int'
+
+// AST-NEXT: HLSLBufferDecl {{.*}} line:29:9 tbuffer B
+// AST-NEXT: HLSLResourceClassAttr {{.*}} Implicit SRV
+// AST-NEXT: HLSLResourceAttr {{.*}} Implicit TBuffer
+// AST-NEXT: FullComment
+// AST-NEXT: ParagraphComment
+// AST-NEXT: TextComment {{.*}} Text=" TBuffer decl."
+// AST-NEXT: VarDecl {{.*}} c 'float'
+// AST-NEXT: VarDecl {{.*}} d 'int'
+// AST-NEXT: CXXRecordDecl {{.*}} implicit class __hostlayout.struct.B 
definition
+// AST: FieldDecl {{.*}} c 'float'
+// AST-NEXT: FieldDecl {{.*}} d 'int'
diff --git a/clang/test/AST/HLSL/cbuffer.hlsl b/clang/test/AST/HLSL/cbuffer.hlsl
index b47ea930c1b57f..c93879d30954a8 100644
--- a/clang/test/AST/HLSL/cbuffer.hlsl
+++ b/clang/test/AST/HLSL/cbuffer.hlsl
@@ -41,15 +41,12 @@ typedef float EmptyArrayTypedef[10][0];
 cbuffer CB {
   // CHECK: VarDecl {{.*}} col:9 used a1 'float'
   float a1;
-
   // CHECK: CXXRecordDecl {{.*}} implicit class __hostlayout.struct.CB 
definition
   // CHECK: FieldDecl {{.*}} a1 'float'
-  // CHECK: VarDecl {{.*}} __handle '__hlsl_resource_t
-  // CHECK-SAME{LITERAL}: [[hlsl::resource_class(CBuffer)]] 
[[hlsl::contained_type(__hostlayout.struct.CB)]]'
 }
 
 // Check that buffer layout struct does not include resources or empty types 
-// CHECK: HLSLBufferDecl {{.*}} line:55:9 cbuffer CB
+// CHECK: HLSLBufferDecl {{.*}} line:52:9 cbuffer CB
 // CHECK: HLSLResourceClassAttr {{.*}} Implicit CBuffer
 // CHECK: HLSLResourceAttr {{.*}} Implicit CBuffer
 cbuffer CB {
@@ -63,16 +60,13 @@ cbuffer CB {
   float d2[0];
   // CHECK: VarDecl {{.*}} col:9 e2 'float'
   float e2;
-
   // CHECK: CXXRecordDecl {{.*}} implicit class __hostlayout.struct.CB.1 
definition
   // CHECK: FieldDecl {{.*}} a2 'float'
   // CHECK-NEXT: FieldDecl {{.*}} e2 'float'
-  // CHECK: VarDecl {{.*}} __handle '__hlsl_resource_t
-  // CHECK-SAME{LITERAL}: [[hlsl::resource_class(CBuffer)]] 
[[hlsl::contained_type(__hostlayout.struct.CB.1)]]'
 }
 
 // Check that layout struct is created for B and the empty struct C is removed
-// CHECK: HLSLBufferDecl {{.*}} line:78:9 cbuffer CB
+// CHECK: HLSLBufferDecl {{.*}} line:72:9 cbuffer CB
 // CHECK: HLSLResourceClassAttr {{.*}} Implicit CBuffer
 // CHECK: HLSLResourceAttr {{.*}} Implicit CBuffer
 cbuffer CB {
@@ -82,38 +76,30 @@ cbuffer CB {
   B s2;
   // CHECK: VarDecl {{.*}} col:12 s3 'CTypedef':'C
   CTypedef s3;
-
   // CHECK: CXXRecordDecl {{.*}} implicit class __hostlayout.struct.B 
definition
   // CHECK: FieldDecl {{.*}} a 'float'
-
   // CHECK: CXXRecordDecl {{.*}} implicit class __hostlayout.struct.CB.2 
definition
   // CHECK: FieldDecl {{.*}} s1 'A'
   // CHECK: FieldDecl {{.*}} s2 '__hostlayout.struct.B'
-  // CHECK-NEXT: VarDecl {{.*}} __handle '__hlsl_resource_t
-  // CHECK-SAME{LITERAL}: [[hlsl::resource_class(CBuffer)]] 
[[hlsl::contained_type(__hostlayout.struct.CB.2)]]'
 }
 
 // check that layout struct is created for D because of its base struct
-// CHECK: HLSLBufferDecl {{.*}} line:100:9 cbuffer CB
+// CHECK: HLSLBufferDecl {{.*}} line:90:9 cbuffer CB
 // CHECK: HLSLResourceClassAttr {{.*}} Implicit CBuffer
 // CHECK: HLSLResourceAttr {{.*}} Implicit CBuffer
 cbuffer CB {
   // CHECK: VarDecl {{.*}} s4 'D'
   D s4;
-
   // CHECK: CXXRecordDecl {{.*}} implicit class __hostlayout.struct.D 
definition
   // CHECK: FieldDecl {{.*}} b 'float'
-
   // CHECK: CXXRecordDecl {{.*}} implicit class __hostlayout.struct.CB.3 
definition
   // CHECK: FieldDecl {{.*}} s4 '__hostlayout.struct.D'
-  // CHECK: VarDecl {{.*}} __handle '__hlsl_resource_t
-  // CHECK-SAME{LITERAL}: [[hlsl::resource_class(CBuffer)]] 
[[hlsl::contained_type(__hostlayout.struct.CB.3)]]'
 }
 
 // check that layout struct is created for E because because its base struct
 // is empty and should be eliminated, and BTypedef should reuse the previously
 // defined '__hostlayout.struct.B' 
-// CHECK: HLSLBufferDecl {{.*}} line:119:9 cbuffer CB
+// CHECK: HLSLBufferDecl {{.*}} line:105:9 cbuffer CB
 // CHECK: HLSLResourceClassAttr {{.*}} Implicit CBuffer
 // CHECK: HLSLResourceAttr {{.*}} Implicit CBuffer
 cbuffer CB {
@@ -121,21 +107,16 @@ cbuffer CB {
   E s5;
   // CHECK: VarDecl {{.*}} s6 'BTypedef':'B'
   BTypedef s6;
-
   // CHECK: CXXRecordDecl {{.*}} implicit class __hostlayout.struct.E 
definition
   // CHECK: FieldDecl {{.*}} c 'float'
-
   // CHECK-NOT: CXXRecordDecl {{.*}} implicit class __hostlayout.struct.B 
definition
-
   // CHECK: CXXRecordDecl {{.*}}  implicit class __hostlayout.struct.CB.4 
definition
   // CHECK: FieldDecl {{.*}} s5 '__hostlayout.struct.E'
   // CHECK: FieldDecl {{.*}} s6 '__hostlayout.struct.B'
-  // CHECK: VarDecl {{.*}} __handle '__hlsl_resource_t
-  // CHECK-SAME{LITERAL}: [[hlsl::resource_class(CBuffer)]] 
[[hlsl::contained_type(__hostlayout.struct.CB.4)]]'
 }
 
 // check that this produces empty layout struct
-// CHECK: HLSLBufferDecl {{.*}} line:141:9 cbuffer CB
+// CHECK: HLSLBufferDecl {{.*}} line:122:9 cbuffer CB
 // CHECK: HLSLResourceClassAttr {{.*}} Implicit CBuffer
 // CHECK: HLSLResourceAttr {{.*}} Implicit CBuffer
 cbuffer CB {
@@ -149,32 +130,25 @@ cbuffer CB {
   RWBuffer<float> Buf;
   // CHECK: VarDecl {{.*}} ea 'EmptyArrayTypedef':'float[10][0]'
   EmptyArrayTypedef ea;
-
   // CHECK: CXXRecordDecl {{.*}} implicit class __hostlayout.struct.CB.5 
definition
   // CHECK-NOT: FieldDecl
-  // CHECK: VarDecl {{.*}} __handle '__hlsl_resource_t
-  // CHECK-SAME{LITERAL}: [[hlsl::resource_class(CBuffer)]] 
[[hlsl::contained_type(__hostlayout.struct.CB.5)]]'
 }
 
 // check host layout struct with compatible base struct
-// CHECK: HLSLBufferDecl {{.*}} line:163:9 cbuffer CB
+// CHECK: HLSLBufferDecl {{.*}} line:141:9 cbuffer CB
 // CHECK: HLSLResourceClassAttr {{.*}} Implicit CBuffer
 // CHECK: HLSLResourceAttr {{.*}} Implicit CBuffer
 cbuffer CB {
   // CHECK: VarDecl {{.*}} s8 'F'
   F s8;
-
   // CHECK: CXXRecordDecl {{.*}} implicit class __hostlayout.struct.F 
definition
   // CHECK: public 'A'
-
   // CHECK: CXXRecordDecl {{.*}} implicit class __hostlayout.struct.CB.6 
definition
   // CHECK: FieldDecl {{.*}} s8 '__hostlayout.struct.F'
-  // CHECK: VarDecl  {{.*}} __handle '__hlsl_resource_t
-  // CHECK-SAME{LITERAL}: [[hlsl::resource_class(CBuffer)]] 
[[hlsl::contained_type(__hostlayout.struct.CB.6)]]'
 }
 
 // anonymous structs
-// CHECK: HLSLBufferDecl {{.*}} line:180:9 cbuffer CB
+// CHECK: HLSLBufferDecl {{.*}} line:154:9 cbuffer CB
 // CHECK: HLSLResourceClassAttr {{.*}} Implicit CBuffer
 // CHECK: HLSLResourceAttr {{.*}} Implicit CBuffer
 cbuffer CB {
@@ -187,8 +161,7 @@ cbuffer CB {
     // CHECK: FieldDecl {{.*}} f 'RWBuffer<float>':'hlsl::RWBuffer<float>'
     RWBuffer<float> f;
   } s9;
-  // CHECK: VarDecl {{.*}} s9 'struct (unnamed struct at 
{{.*}}cbuffer.hlsl:182:3
-  
+  // CHECK: VarDecl {{.*}} s9 'struct (unnamed struct at 
{{.*}}cbuffer.hlsl:156:3
   // CHECK: CXXRecordDecl {{.*}} struct definition
   struct {
     // CHECK: FieldDecl {{.*}} g 'int'
@@ -196,22 +169,17 @@ cbuffer CB {
     // CHECK: FieldDecl {{.*}} f 'RWBuffer<float>':'hlsl::RWBuffer<float>'
     RWBuffer<float> f;
   } s10;
-  // CHECK: VarDecl {{.*}} s10 'struct (unnamed struct at 
{{.*}}cbuffer.hlsl:193:3
-
+  // CHECK: VarDecl {{.*}} s10 'struct (unnamed struct at 
{{.*}}cbuffer.hlsl:166:3
   // CHECK: CXXRecordDecl {{.*}} implicit class __hostlayout.struct.anon 
definition
   // CHECK: FieldDecl {{.*}} e 'float'
-
   // CHECK: CXXRecordDecl {{.*}} implicit class __hostlayout.struct.anon.1 
definition
   // CHECK: FieldDecl {{.*}} g 'int'
-
   // CHECK: CXXRecordDecl {{.*}} implicit class __hostlayout.struct.CB.7 
definition
   // CHECK: FieldDecl {{.*}} s9 '__hostlayout.struct.anon'
   // CHECK: FieldDecl {{.*}} s10 '__hostlayout.struct.anon.1'
-  // CHECK-NEXT: VarDecl {{.*}} __handle '__hlsl_resource_t
-  // CHECK-SAME{LITERAL} [[hlsl::resource_class(CBuffer)]] 
[[hlsl::contained_type(__hostlayout.struct.CB.7)]]'
 }
 
-// Add uses for the constant buffer declarations so they are not optimized 
awayexport 
+// Add uses for the constant buffer declarations so they are not optimized away
 export float foo() {
   return a1 + a2 + s1.a + s4.b + s5.c + s8.a + s9.e;
 }
diff --git a/clang/test/AST/HLSL/pch_hlsl_buffer.hlsl 
b/clang/test/AST/HLSL/pch_hlsl_buffer.hlsl
index 9e8ab95acf8178..8c0253fd526387 100644
--- a/clang/test/AST/HLSL/pch_hlsl_buffer.hlsl
+++ b/clang/test/AST/HLSL/pch_hlsl_buffer.hlsl
@@ -17,29 +17,25 @@ float foo() {
 }
 
 // Make sure cbuffer/tbuffer works for PCH.
-// CHECK:HLSLBufferDecl 0x{{[0-9a-f]+}} <{{.*}}:7:1, line:9:1> line:7:9 
imported <undeserialized declarations> cbuffer A
-// CHECK-NEXT:HLSLResourceClassAttr {{.*}} <<invalid sloc>> Implicit CBuffer
-// CHECK-NEXT:HLSLResourceAttr {{.*}} <<invalid sloc>> Implicit CBuffer
-// CHECK-NEXT:VarDecl 0x[[A:[0-9a-f]+]] <line:8:3, col:9> col:9 imported used 
a 'float'
-// CHECK-NEXT:CXXRecordDecl 0x{{[0-9a-f]+}} {{.*}} imported implicit 
<undeserialized declarations> class __hostlayout.struct.A definition
-// CHECK:FieldDecl 0x{{[0-9a-f]+}} {{.*}} imported a 'float'
-// CHECK-NEXT:VarDecl 0x{{[0-9a-f]+}} {{.*}} imported __handle 
'__hlsl_resource_t
-// CHECK-SAME{LITERAL}: [[hlsl::resource_class(CBuffer)]] 
[[hlsl::contained_type(__hostlayout.struct.A)]]'
+// CHECK: HLSLBufferDecl {{.*}} line:7:9 imported <undeserialized 
declarations> cbuffer A
+// CHECK-NEXT: HLSLResourceClassAttr {{.*}} Implicit CBuffer
+// CHECK-NEXT: HLSLResourceAttr {{.*}} Implicit CBuffer
+// CHECK-NEXT: VarDecl 0x[[A:[0-9a-f]+]] {{.*}} imported used a 'float'
+// CHECK-NEXT: CXXRecordDecl {{.*}} imported implicit <undeserialized 
declarations> class __hostlayout.struct.A definition
+// CHECK: FieldDecl {{.*}} imported a 'float'
 
-// CHECK:HLSLBufferDecl 0x{{[0-9a-f]+}} <line:11:1, line:13:1> line:11:9 
imported <undeserialized declarations> tbuffer B
-// CHECK-NEXT:HLSLResourceClassAttr {{.*}} <<invalid sloc>> Implicit SRV
-// CHECK-NEXT:HLSLResourceAttr {{.*}} <<invalid sloc>> Implicit TBuffer
-// CHECK-NEXT:VarDecl 0x[[B:[0-9a-f]+]] <line:12:3, col:9> col:9 imported used 
b 'float'
-// CHECK-NEXT:CXXRecordDecl 0x{{[0-9a-f]+}} {{.*}} imported implicit 
<undeserialized declarations> class __hostlayout.struct.B definition
-// CHECK:FieldDecl 0x{{[0-9a-f]+}} {{.*}} imported b 'float'
-// CHECK-NEXT:VarDecl 0x{{[0-9a-f]+}} {{.*}} imported __handle 
'__hlsl_resource_t
-// CHECK-SAME{LITERAL}: [[hlsl::resource_class(SRV)]] 
[[hlsl::contained_type(__hostlayout.struct.B)]]'
+// CHECK: HLSLBufferDecl {{.*}} line:11:9 imported <undeserialized 
declarations> tbuffer B
+// CHECK-NEXT: HLSLResourceClassAttr {{.*}} Implicit SRV
+// CHECK-NEXT: HLSLResourceAttr {{.*}} Implicit TBuffer
+// CHECK-NEXT: VarDecl 0x[[B:[0-9a-f]+]] {{.*}} imported used b 'float'
+// CHECK-NEXT: CXXRecordDecl 0x{{[0-9a-f]+}} {{.*}} imported implicit 
<undeserialized declarations> class __hostlayout.struct.B definition
+// CHECK: FieldDecl 0x{{[0-9a-f]+}} {{.*}} imported b 'float'
 
-// CHECK-NEXT:FunctionDecl 0x{{[0-9a-f]+}} <line:15:1, line:17:1> line:15:7 
imported foo 'float ()'
-// CHECK-NEXT:CompoundStmt 0x{{[0-9a-f]+}} <col:13, line:17:1>
-// CHECK-NEXT:ReturnStmt 0x{{[0-9a-f]+}} <line:16:3, col:14>
-// CHECK-NEXT:BinaryOperator 0x{{[0-9a-f]+}} <col:10, col:14> 'float' '+'
-// CHECK-NEXT:ImplicitCastExpr 0x{{[0-9a-f]+}} <col:10> 'float' 
<LValueToRValue>
-// CHECK-NEXT:`-DeclRefExpr 0x{{[0-9a-f]+}} <col:10> 'float' lvalue Var 
0x[[A]] 'a' 'float'
-// CHECK-NEXT:`-ImplicitCastExpr 0x{{[0-9a-f]+}} <col:14> 'float' 
<LValueToRValue>
-// CHECK-NEXT:`-DeclRefExpr 0x{{[0-9a-f]+}} <col:14> 'float' lvalue Var 
0x[[B]] 'b' 'float'
+// CHECK-NEXT: FunctionDecl {{.*}} line:15:7 imported foo 'float ()'
+// CHECK-NEXT: CompoundStmt {{.*}}
+// CHECK-NEXT: ReturnStmt {{.*}}
+// CHECK-NEXT: BinaryOperator {{.*}} 'float' '+'
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <LValueToRValue>
+// CHECK-NEXT: DeclRefExpr {{.*}} 'float' lvalue Var 0x[[A]] 'a' 'float'
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <LValueToRValue>
+// CHECK-NEXT: DeclRefExpr {{.*}} 'float' lvalue Var 0x[[B]] 'b' 'float'

>From fc939dbfdd35e22e2702313dfbe4499f35985de4 Mon Sep 17 00:00:00 2001
From: Helena Kotas <heko...@microsoft.com>
Date: Tue, 14 Jan 2025 12:39:21 -0800
Subject: [PATCH 3/8] One more char to revert things to previous state

---
 clang/lib/CodeGen/CGHLSLRuntime.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/lib/CodeGen/CGHLSLRuntime.h 
b/clang/lib/CodeGen/CGHLSLRuntime.h
index 7858abb9e51e96..00e110e8e6fa27 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.h
+++ b/clang/lib/CodeGen/CGHLSLRuntime.h
@@ -169,7 +169,7 @@ class CGHLSLRuntime {
                                    llvm::hlsl::ElementType ET,
                                    BufferResBinding &Binding);
   void addConstant(VarDecl *D, Buffer &CB);
-  void addBufferDecls(const DeclContext *D, Buffer &CB);
+  void addBufferDecls(const DeclContext *DC, Buffer &CB);
   llvm::Triple::ArchType getArch();
   llvm::SmallVector<Buffer> Buffers;
 

>From 02339941348fa95123dff2f4d0c1f19568d3406b Mon Sep 17 00:00:00 2001
From: Helena Kotas <heko...@microsoft.com>
Date: Thu, 16 Jan 2025 11:50:23 -0800
Subject: [PATCH 4/8] Make the layout struct name shorter

Use "__layout." prefix instead of "__hostlayout.struct." to make the text 
output more concise for both AST and LLVM IR.
---
 clang/lib/Sema/SemaHLSL.cpp                   | 10 ++--
 .../ast-dump-comment-cbuffer-tbuffer.hlsl     |  4 +-
 clang/test/AST/HLSL/cbuffer.hlsl              | 46 +++++++++----------
 clang/test/AST/HLSL/pch_hlsl_buffer.hlsl      |  4 +-
 4 files changed, 31 insertions(+), 33 deletions(-)

diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index 84b69e0db4c2b9..9bbd0ad1eb4a64 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -318,7 +318,7 @@ static IdentifierInfo *getHostLayoutStructName(Sema &S,
     MustBeUnique = true;
   }
 
-  std::string Name = "__hostlayout.struct." + NameBase;
+  std::string Name = "__layout." + NameBase;
   IdentifierInfo *II = &AST.Idents.get(Name, tok::TokenKind::identifier);
   if (!MustBeUnique)
     return II;
@@ -443,8 +443,8 @@ static CXXRecordDecl *createHostLayoutStruct(Sema &S, 
CXXRecordDecl *StructDecl,
 // - empty structs
 // - zero-sized arrays
 // - non-variable declarations
-static CXXRecordDecl *createHostLayoutStructForBuffer(Sema &S,
-                                                      HLSLBufferDecl *BufDecl) 
{
+// The layour struct will be added to the HLSLBufferDecl declarations.
+void createHostLayoutStructForBuffer(Sema &S, HLSLBufferDecl *BufDecl) {
   ASTContext &AST = S.getASTContext();
   IdentifierInfo *II = getHostLayoutStructName(S, BufDecl->getIdentifier(),
                                                true, 
BufDecl->getDeclContext());
@@ -466,7 +466,6 @@ static CXXRecordDecl *createHostLayoutStructForBuffer(Sema 
&S,
   }
   LS->completeDefinition();
   BufDecl->addDecl(LS);
-  return LS;
 }
 
 // Handle end of cbuffer/tbuffer declaration
@@ -477,8 +476,7 @@ void SemaHLSL::ActOnFinishBuffer(Decl *Dcl, SourceLocation 
RBrace) {
   validatePackoffset(SemaRef, BufDecl);
 
   // create buffer layout struct
-  CXXRecordDecl *LayoutStruct =
-      createHostLayoutStructForBuffer(SemaRef, BufDecl);
+  createHostLayoutStructForBuffer(SemaRef, BufDecl);
 
   SemaRef.PopDeclContext();
 }
diff --git a/clang/test/AST/HLSL/ast-dump-comment-cbuffer-tbuffer.hlsl 
b/clang/test/AST/HLSL/ast-dump-comment-cbuffer-tbuffer.hlsl
index f18ae022a1dd6a..aebb7c0e8da334 100644
--- a/clang/test/AST/HLSL/ast-dump-comment-cbuffer-tbuffer.hlsl
+++ b/clang/test/AST/HLSL/ast-dump-comment-cbuffer-tbuffer.hlsl
@@ -45,7 +45,7 @@ tbuffer B {
 // AST-NEXT: TextComment {{.*}} Text=" CBuffer decl."
 // AST-NEXT: VarDecl {{.*}} a 'float'
 // AST-NEXT: VarDecl {{.*}} b 'int'
-// AST-NEXT: CXXRecordDecl {{.*}} implicit class __hostlayout.struct.A 
definition
+// AST-NEXT: CXXRecordDecl {{.*}} implicit class __layout.A definition
 // AST: FieldDecl {{.*}} a 'float'
 // AST-NEXT: FieldDecl {{.*}} b 'int'
 
@@ -57,6 +57,6 @@ tbuffer B {
 // AST-NEXT: TextComment {{.*}} Text=" TBuffer decl."
 // AST-NEXT: VarDecl {{.*}} c 'float'
 // AST-NEXT: VarDecl {{.*}} d 'int'
-// AST-NEXT: CXXRecordDecl {{.*}} implicit class __hostlayout.struct.B 
definition
+// AST-NEXT: CXXRecordDecl {{.*}} implicit class __layout.B definition
 // AST: FieldDecl {{.*}} c 'float'
 // AST-NEXT: FieldDecl {{.*}} d 'int'
diff --git a/clang/test/AST/HLSL/cbuffer.hlsl b/clang/test/AST/HLSL/cbuffer.hlsl
index c93879d30954a8..a20485606a79d0 100644
--- a/clang/test/AST/HLSL/cbuffer.hlsl
+++ b/clang/test/AST/HLSL/cbuffer.hlsl
@@ -41,7 +41,7 @@ typedef float EmptyArrayTypedef[10][0];
 cbuffer CB {
   // CHECK: VarDecl {{.*}} col:9 used a1 'float'
   float a1;
-  // CHECK: CXXRecordDecl {{.*}} implicit class __hostlayout.struct.CB 
definition
+  // CHECK: CXXRecordDecl {{.*}} implicit class __layout.CB definition
   // CHECK: FieldDecl {{.*}} a1 'float'
 }
 
@@ -60,7 +60,7 @@ cbuffer CB {
   float d2[0];
   // CHECK: VarDecl {{.*}} col:9 e2 'float'
   float e2;
-  // CHECK: CXXRecordDecl {{.*}} implicit class __hostlayout.struct.CB.1 
definition
+  // CHECK: CXXRecordDecl {{.*}} implicit class __layout.CB.1 definition
   // CHECK: FieldDecl {{.*}} a2 'float'
   // CHECK-NEXT: FieldDecl {{.*}} e2 'float'
 }
@@ -76,11 +76,11 @@ cbuffer CB {
   B s2;
   // CHECK: VarDecl {{.*}} col:12 s3 'CTypedef':'C
   CTypedef s3;
-  // CHECK: CXXRecordDecl {{.*}} implicit class __hostlayout.struct.B 
definition
+  // CHECK: CXXRecordDecl {{.*}} implicit class __layout.B definition
   // CHECK: FieldDecl {{.*}} a 'float'
-  // CHECK: CXXRecordDecl {{.*}} implicit class __hostlayout.struct.CB.2 
definition
+  // CHECK: CXXRecordDecl {{.*}} implicit class __layout.CB.2 definition
   // CHECK: FieldDecl {{.*}} s1 'A'
-  // CHECK: FieldDecl {{.*}} s2 '__hostlayout.struct.B'
+  // CHECK: FieldDecl {{.*}} s2 '__layout.B'
 }
 
 // check that layout struct is created for D because of its base struct
@@ -90,15 +90,15 @@ cbuffer CB {
 cbuffer CB {
   // CHECK: VarDecl {{.*}} s4 'D'
   D s4;
-  // CHECK: CXXRecordDecl {{.*}} implicit class __hostlayout.struct.D 
definition
+  // CHECK: CXXRecordDecl {{.*}} implicit class __layout.D definition
   // CHECK: FieldDecl {{.*}} b 'float'
-  // CHECK: CXXRecordDecl {{.*}} implicit class __hostlayout.struct.CB.3 
definition
-  // CHECK: FieldDecl {{.*}} s4 '__hostlayout.struct.D'
+  // CHECK: CXXRecordDecl {{.*}} implicit class __layout.CB.3 definition
+  // CHECK: FieldDecl {{.*}} s4 '__layout.D'
 }
 
 // check that layout struct is created for E because because its base struct
 // is empty and should be eliminated, and BTypedef should reuse the previously
-// defined '__hostlayout.struct.B' 
+// defined '__layout.B' 
 // CHECK: HLSLBufferDecl {{.*}} line:105:9 cbuffer CB
 // CHECK: HLSLResourceClassAttr {{.*}} Implicit CBuffer
 // CHECK: HLSLResourceAttr {{.*}} Implicit CBuffer
@@ -107,12 +107,12 @@ cbuffer CB {
   E s5;
   // CHECK: VarDecl {{.*}} s6 'BTypedef':'B'
   BTypedef s6;
-  // CHECK: CXXRecordDecl {{.*}} implicit class __hostlayout.struct.E 
definition
+  // CHECK: CXXRecordDecl {{.*}} implicit class __layout.E definition
   // CHECK: FieldDecl {{.*}} c 'float'
-  // CHECK-NOT: CXXRecordDecl {{.*}} implicit class __hostlayout.struct.B 
definition
-  // CHECK: CXXRecordDecl {{.*}}  implicit class __hostlayout.struct.CB.4 
definition
-  // CHECK: FieldDecl {{.*}} s5 '__hostlayout.struct.E'
-  // CHECK: FieldDecl {{.*}} s6 '__hostlayout.struct.B'
+  // CHECK-NOT: CXXRecordDecl {{.*}} implicit class __layout.B definition
+  // CHECK: CXXRecordDecl {{.*}}  implicit class __layout.CB.4 definition
+  // CHECK: FieldDecl {{.*}} s5 '__layout.E'
+  // CHECK: FieldDecl {{.*}} s6 '__layout.B'
 }
 
 // check that this produces empty layout struct
@@ -130,7 +130,7 @@ cbuffer CB {
   RWBuffer<float> Buf;
   // CHECK: VarDecl {{.*}} ea 'EmptyArrayTypedef':'float[10][0]'
   EmptyArrayTypedef ea;
-  // CHECK: CXXRecordDecl {{.*}} implicit class __hostlayout.struct.CB.5 
definition
+  // CHECK: CXXRecordDecl {{.*}} implicit class __layout.CB.5 definition
   // CHECK-NOT: FieldDecl
 }
 
@@ -141,10 +141,10 @@ cbuffer CB {
 cbuffer CB {
   // CHECK: VarDecl {{.*}} s8 'F'
   F s8;
-  // CHECK: CXXRecordDecl {{.*}} implicit class __hostlayout.struct.F 
definition
+  // CHECK: CXXRecordDecl {{.*}} implicit class __layout.F definition
   // CHECK: public 'A'
-  // CHECK: CXXRecordDecl {{.*}} implicit class __hostlayout.struct.CB.6 
definition
-  // CHECK: FieldDecl {{.*}} s8 '__hostlayout.struct.F'
+  // CHECK: CXXRecordDecl {{.*}} implicit class __layout.CB.6 definition
+  // CHECK: FieldDecl {{.*}} s8 '__layout.F'
 }
 
 // anonymous structs
@@ -170,13 +170,13 @@ cbuffer CB {
     RWBuffer<float> f;
   } s10;
   // CHECK: VarDecl {{.*}} s10 'struct (unnamed struct at 
{{.*}}cbuffer.hlsl:166:3
-  // CHECK: CXXRecordDecl {{.*}} implicit class __hostlayout.struct.anon 
definition
+  // CHECK: CXXRecordDecl {{.*}} implicit class __layout.anon definition
   // CHECK: FieldDecl {{.*}} e 'float'
-  // CHECK: CXXRecordDecl {{.*}} implicit class __hostlayout.struct.anon.1 
definition
+  // CHECK: CXXRecordDecl {{.*}} implicit class __layout.anon.1 definition
   // CHECK: FieldDecl {{.*}} g 'int'
-  // CHECK: CXXRecordDecl {{.*}} implicit class __hostlayout.struct.CB.7 
definition
-  // CHECK: FieldDecl {{.*}} s9 '__hostlayout.struct.anon'
-  // CHECK: FieldDecl {{.*}} s10 '__hostlayout.struct.anon.1'
+  // CHECK: CXXRecordDecl {{.*}} implicit class __layout.CB.7 definition
+  // CHECK: FieldDecl {{.*}} s9 '__layout.anon'
+  // CHECK: FieldDecl {{.*}} s10 '__layout.anon.1'
 }
 
 // Add uses for the constant buffer declarations so they are not optimized away
diff --git a/clang/test/AST/HLSL/pch_hlsl_buffer.hlsl 
b/clang/test/AST/HLSL/pch_hlsl_buffer.hlsl
index 8c0253fd526387..02310c068c166e 100644
--- a/clang/test/AST/HLSL/pch_hlsl_buffer.hlsl
+++ b/clang/test/AST/HLSL/pch_hlsl_buffer.hlsl
@@ -21,14 +21,14 @@ float foo() {
 // CHECK-NEXT: HLSLResourceClassAttr {{.*}} Implicit CBuffer
 // CHECK-NEXT: HLSLResourceAttr {{.*}} Implicit CBuffer
 // CHECK-NEXT: VarDecl 0x[[A:[0-9a-f]+]] {{.*}} imported used a 'float'
-// CHECK-NEXT: CXXRecordDecl {{.*}} imported implicit <undeserialized 
declarations> class __hostlayout.struct.A definition
+// CHECK-NEXT: CXXRecordDecl {{.*}} imported implicit <undeserialized 
declarations> class __layout.A definition
 // CHECK: FieldDecl {{.*}} imported a 'float'
 
 // CHECK: HLSLBufferDecl {{.*}} line:11:9 imported <undeserialized 
declarations> tbuffer B
 // CHECK-NEXT: HLSLResourceClassAttr {{.*}} Implicit SRV
 // CHECK-NEXT: HLSLResourceAttr {{.*}} Implicit TBuffer
 // CHECK-NEXT: VarDecl 0x[[B:[0-9a-f]+]] {{.*}} imported used b 'float'
-// CHECK-NEXT: CXXRecordDecl 0x{{[0-9a-f]+}} {{.*}} imported implicit 
<undeserialized declarations> class __hostlayout.struct.B definition
+// CHECK-NEXT: CXXRecordDecl 0x{{[0-9a-f]+}} {{.*}} imported implicit 
<undeserialized declarations> class __layout.B definition
 // CHECK: FieldDecl 0x{{[0-9a-f]+}} {{.*}} imported b 'float'
 
 // CHECK-NEXT: FunctionDecl {{.*}} line:15:7 imported foo 'float ()'

>From 75edd2b8a2b8749c5aa5bfa225f7a71b5ea7524a Mon Sep 17 00:00:00 2001
From: Helena Kotas <heko...@microsoft.com>
Date: Tue, 21 Jan 2025 22:41:58 -0800
Subject: [PATCH 5/8] code review feedback - rename function and layout struct,
 add static asserts

---
 clang/lib/Sema/SemaHLSL.cpp                   | 38 ++++----
 .../ast-dump-comment-cbuffer-tbuffer.hlsl     |  4 +-
 clang/test/AST/HLSL/cbuffer.hlsl              | 95 ++++++++++++-------
 clang/test/AST/HLSL/pch_hlsl_buffer.hlsl      |  4 +-
 4 files changed, 83 insertions(+), 58 deletions(-)

diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index 9bbd0ad1eb4a64..8796848805e110 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -265,29 +265,31 @@ static bool isZeroSizedArray(const ConstantArrayType 
*CAT) {
   return CAT != nullptr;
 }
 
-// Returns true if the struct can be used inside HLSL Buffer which means
-// that it does not contain intangible types, empty structs, zero-sized arrays,
-// and the same is true for its base or embedded structs.
-bool isStructHLSLBufferCompatible(const CXXRecordDecl *RD) {
-  if (RD->getTypeForDecl()->isHLSLIntangibleType() ||
-      (RD->field_empty() && RD->getNumBases() == 0))
-    return false;
+// Returns true if the struct contains at least one element that prevents it
+// from being included inside HLSL Buffer as is, such as an intangible type,
+// empty struct, or zero-sized array. If it does, a new implicit layout struct
+// needs to be created for HLSL Buffer use that will exclude these unwanted
+// declarations (see createHostLayoutStruct function).
+static bool requiresImplicitBufferLayoutStructure(const CXXRecordDecl *RD) {
+  if (RD->getTypeForDecl()->isHLSLIntangibleType() || RD->isEmpty())
+    return true;
   // check fields
   for (const FieldDecl *Field : RD->fields()) {
     QualType Ty = Field->getType();
     if (Ty->isRecordType()) {
-      if (!isStructHLSLBufferCompatible(Ty->getAsCXXRecordDecl()))
-        return false;
+      if (requiresImplicitBufferLayoutStructure(Ty->getAsCXXRecordDecl()))
+        return true;
     } else if (Ty->isConstantArrayType()) {
       if (isZeroSizedArray(cast<ConstantArrayType>(Ty)))
-        return false;
+        return true;
     }
   }
   // check bases
   for (const CXXBaseSpecifier &Base : RD->bases())
-    if (!isStructHLSLBufferCompatible(Base.getType()->getAsCXXRecordDecl()))
-      return false;
-  return true;
+    if (requiresImplicitBufferLayoutStructure(
+            Base.getType()->getAsCXXRecordDecl()))
+      return true;
+  return false;
 }
 
 static CXXRecordDecl *findRecordDecl(Sema &S, IdentifierInfo *II,
@@ -318,7 +320,7 @@ static IdentifierInfo *getHostLayoutStructName(Sema &S,
     MustBeUnique = true;
   }
 
-  std::string Name = "__layout." + NameBase;
+  std::string Name = "__layout_" + NameBase;
   IdentifierInfo *II = &AST.Idents.get(Name, tok::TokenKind::identifier);
   if (!MustBeUnique)
     return II;
@@ -326,7 +328,7 @@ static IdentifierInfo *getHostLayoutStructName(Sema &S,
   unsigned suffix = 0;
   while (true) {
     if (suffix != 0)
-      II = &AST.Idents.get((llvm::Twine(Name) + "." + Twine(suffix)).str(),
+      II = &AST.Idents.get((llvm::Twine(Name) + "_" + Twine(suffix)).str(),
                            tok::TokenKind::identifier);
     if (!findRecordDecl(S, II, DC))
       return II;
@@ -354,7 +356,7 @@ static FieldDecl *createFieldForHostLayoutStruct(Sema &S, 
const Type *Ty,
     if (isResourceRecordType(Ty))
       return nullptr;
     CXXRecordDecl *RD = Ty->getAsCXXRecordDecl();
-    if (!isStructHLSLBufferCompatible(RD)) {
+    if (requiresImplicitBufferLayoutStructure(RD)) {
       RD = createHostLayoutStruct(S, RD, BufDecl);
       if (!RD)
         return nullptr;
@@ -383,7 +385,7 @@ static FieldDecl *createFieldForHostLayoutStruct(Sema &S, 
const Type *Ty,
 // Returns nullptr if the resulting layout struct would be empty.
 static CXXRecordDecl *createHostLayoutStruct(Sema &S, CXXRecordDecl 
*StructDecl,
                                              HLSLBufferDecl *BufDecl) {
-  assert(!isStructHLSLBufferCompatible(StructDecl) &&
+  assert(requiresImplicitBufferLayoutStructure(StructDecl) &&
          "struct is already HLSL buffer compatible");
 
   ASTContext &AST = S.getASTContext();
@@ -406,7 +408,7 @@ static CXXRecordDecl *createHostLayoutStruct(Sema &S, 
CXXRecordDecl *StructDecl,
     assert(NumBases == 1 && "HLSL supports only one base type");
     CXXBaseSpecifier Base = *StructDecl->bases_begin();
     CXXRecordDecl *BaseDecl = Base.getType()->getAsCXXRecordDecl();
-    if (!isStructHLSLBufferCompatible(BaseDecl)) {
+    if (requiresImplicitBufferLayoutStructure(BaseDecl)) {
       BaseDecl = createHostLayoutStruct(S, BaseDecl, BufDecl);
       if (BaseDecl) {
         TypeSourceInfo *TSI = AST.getTrivialTypeSourceInfo(
diff --git a/clang/test/AST/HLSL/ast-dump-comment-cbuffer-tbuffer.hlsl 
b/clang/test/AST/HLSL/ast-dump-comment-cbuffer-tbuffer.hlsl
index aebb7c0e8da334..0bff3ae1440379 100644
--- a/clang/test/AST/HLSL/ast-dump-comment-cbuffer-tbuffer.hlsl
+++ b/clang/test/AST/HLSL/ast-dump-comment-cbuffer-tbuffer.hlsl
@@ -45,7 +45,7 @@ tbuffer B {
 // AST-NEXT: TextComment {{.*}} Text=" CBuffer decl."
 // AST-NEXT: VarDecl {{.*}} a 'float'
 // AST-NEXT: VarDecl {{.*}} b 'int'
-// AST-NEXT: CXXRecordDecl {{.*}} implicit class __layout.A definition
+// AST-NEXT: CXXRecordDecl {{.*}} implicit class __layout_A definition
 // AST: FieldDecl {{.*}} a 'float'
 // AST-NEXT: FieldDecl {{.*}} b 'int'
 
@@ -57,6 +57,6 @@ tbuffer B {
 // AST-NEXT: TextComment {{.*}} Text=" TBuffer decl."
 // AST-NEXT: VarDecl {{.*}} c 'float'
 // AST-NEXT: VarDecl {{.*}} d 'int'
-// AST-NEXT: CXXRecordDecl {{.*}} implicit class __layout.B definition
+// AST-NEXT: CXXRecordDecl {{.*}} implicit class __layout_B definition
 // AST: FieldDecl {{.*}} c 'float'
 // AST-NEXT: FieldDecl {{.*}} d 'int'
diff --git a/clang/test/AST/HLSL/cbuffer.hlsl b/clang/test/AST/HLSL/cbuffer.hlsl
index a20485606a79d0..d78946cd99649b 100644
--- a/clang/test/AST/HLSL/cbuffer.hlsl
+++ b/clang/test/AST/HLSL/cbuffer.hlsl
@@ -35,18 +35,28 @@ struct F : A {
 
 typedef float EmptyArrayTypedef[10][0];
 
-// CHECK: HLSLBufferDecl {{.*}} line:41:9 cbuffer CB
+struct OneFloat {
+  float a;
+};
+
+struct TwoFloats {
+  float a;
+  float b;
+};
+
+// CHECK: HLSLBufferDecl {{.*}} line:50:9 cbuffer CB
 // CHECK: HLSLResourceClassAttr {{.*}} Implicit CBuffer
 // CHECK: HLSLResourceAttr {{.*}} Implicit CBuffer
 cbuffer CB {
   // CHECK: VarDecl {{.*}} col:9 used a1 'float'
   float a1;
-  // CHECK: CXXRecordDecl {{.*}} implicit class __layout.CB definition
+  // CHECK: CXXRecordDecl {{.*}} implicit referenced class __layout_CB 
definition
   // CHECK: FieldDecl {{.*}} a1 'float'
 }
+_Static_assert(__builtin_hlsl_is_scalarized_layout_compatible(OneFloat, 
__layout_CB), "");
 
 // Check that buffer layout struct does not include resources or empty types 
-// CHECK: HLSLBufferDecl {{.*}} line:52:9 cbuffer CB
+// CHECK: HLSLBufferDecl {{.*}} line:62:9 cbuffer CB
 // CHECK: HLSLResourceClassAttr {{.*}} Implicit CBuffer
 // CHECK: HLSLResourceAttr {{.*}} Implicit CBuffer
 cbuffer CB {
@@ -60,13 +70,14 @@ cbuffer CB {
   float d2[0];
   // CHECK: VarDecl {{.*}} col:9 e2 'float'
   float e2;
-  // CHECK: CXXRecordDecl {{.*}} implicit class __layout.CB.1 definition
+  // CHECK: CXXRecordDecl {{.*}} implicit referenced class __layout_CB_1 
definition
   // CHECK: FieldDecl {{.*}} a2 'float'
   // CHECK-NEXT: FieldDecl {{.*}} e2 'float'
 }
+_Static_assert(__builtin_hlsl_is_scalarized_layout_compatible(TwoFloats, 
__layout_CB_1), "");
 
 // Check that layout struct is created for B and the empty struct C is removed
-// CHECK: HLSLBufferDecl {{.*}} line:72:9 cbuffer CB
+// CHECK: HLSLBufferDecl {{.*}} line:83:9 cbuffer CB
 // CHECK: HLSLResourceClassAttr {{.*}} Implicit CBuffer
 // CHECK: HLSLResourceAttr {{.*}} Implicit CBuffer
 cbuffer CB {
@@ -76,30 +87,35 @@ cbuffer CB {
   B s2;
   // CHECK: VarDecl {{.*}} col:12 s3 'CTypedef':'C
   CTypedef s3;
-  // CHECK: CXXRecordDecl {{.*}} implicit class __layout.B definition
+  // CHECK: CXXRecordDecl {{.*}} implicit referenced class __layout_B 
definition
   // CHECK: FieldDecl {{.*}} a 'float'
-  // CHECK: CXXRecordDecl {{.*}} implicit class __layout.CB.2 definition
+  // CHECK: CXXRecordDecl {{.*}} implicit referenced class __layout_CB_2 
definition
   // CHECK: FieldDecl {{.*}} s1 'A'
-  // CHECK: FieldDecl {{.*}} s2 '__layout.B'
+  // CHECK: FieldDecl {{.*}} s2 '__layout_B'
 }
+_Static_assert(__builtin_hlsl_is_scalarized_layout_compatible(OneFloat, 
__layout_B), "");
+_Static_assert(__builtin_hlsl_is_scalarized_layout_compatible(TwoFloats, 
__layout_CB_2), "");
 
 // check that layout struct is created for D because of its base struct
-// CHECK: HLSLBufferDecl {{.*}} line:90:9 cbuffer CB
+// CHECK: HLSLBufferDecl {{.*}} line:103:9 cbuffer CB
 // CHECK: HLSLResourceClassAttr {{.*}} Implicit CBuffer
 // CHECK: HLSLResourceAttr {{.*}} Implicit CBuffer
 cbuffer CB {
   // CHECK: VarDecl {{.*}} s4 'D'
   D s4;
-  // CHECK: CXXRecordDecl {{.*}} implicit class __layout.D definition
+  // CHECK: CXXRecordDecl {{.*}} implicit referenced class __layout_D 
definition
+  // CHECK: public '__layout_B'
   // CHECK: FieldDecl {{.*}} b 'float'
-  // CHECK: CXXRecordDecl {{.*}} implicit class __layout.CB.3 definition
-  // CHECK: FieldDecl {{.*}} s4 '__layout.D'
+  // CHECK: CXXRecordDecl {{.*}} implicit referenced class __layout_CB_3 
definition
+  // CHECK: FieldDecl {{.*}} s4 '__layout_D'
 }
+_Static_assert(__builtin_hlsl_is_scalarized_layout_compatible(TwoFloats, 
__layout_D), "");
+_Static_assert(__builtin_hlsl_is_scalarized_layout_compatible(TwoFloats, 
__layout_CB_3), "");
 
 // check that layout struct is created for E because because its base struct
 // is empty and should be eliminated, and BTypedef should reuse the previously
-// defined '__layout.B' 
-// CHECK: HLSLBufferDecl {{.*}} line:105:9 cbuffer CB
+// defined '__layout_B' 
+// CHECK: HLSLBufferDecl {{.*}} line:121:9 cbuffer CB
 // CHECK: HLSLResourceClassAttr {{.*}} Implicit CBuffer
 // CHECK: HLSLResourceAttr {{.*}} Implicit CBuffer
 cbuffer CB {
@@ -107,16 +123,18 @@ cbuffer CB {
   E s5;
   // CHECK: VarDecl {{.*}} s6 'BTypedef':'B'
   BTypedef s6;
-  // CHECK: CXXRecordDecl {{.*}} implicit class __layout.E definition
+  // CHECK: CXXRecordDecl {{.*}} implicit referenced class __layout_E 
definition
   // CHECK: FieldDecl {{.*}} c 'float'
-  // CHECK-NOT: CXXRecordDecl {{.*}} implicit class __layout.B definition
-  // CHECK: CXXRecordDecl {{.*}}  implicit class __layout.CB.4 definition
-  // CHECK: FieldDecl {{.*}} s5 '__layout.E'
-  // CHECK: FieldDecl {{.*}} s6 '__layout.B'
+  // CHECK-NOT: CXXRecordDecl {{.*}} class __layout_B definition
+  // CHECK: CXXRecordDecl {{.*}}  implicit referenced class __layout_CB_4 
definition
+  // CHECK: FieldDecl {{.*}} s5 '__layout_E'
+  // CHECK: FieldDecl {{.*}} s6 '__layout_B'
 }
+_Static_assert(__builtin_hlsl_is_scalarized_layout_compatible(OneFloat, 
__layout_E), "");
+_Static_assert(__builtin_hlsl_is_scalarized_layout_compatible(TwoFloats, 
__layout_CB_4), "");
 
 // check that this produces empty layout struct
-// CHECK: HLSLBufferDecl {{.*}} line:122:9 cbuffer CB
+// CHECK: HLSLBufferDecl {{.*}} line:140:9 cbuffer CB
 // CHECK: HLSLResourceClassAttr {{.*}} Implicit CBuffer
 // CHECK: HLSLResourceAttr {{.*}} Implicit CBuffer
 cbuffer CB {
@@ -130,25 +148,27 @@ cbuffer CB {
   RWBuffer<float> Buf;
   // CHECK: VarDecl {{.*}} ea 'EmptyArrayTypedef':'float[10][0]'
   EmptyArrayTypedef ea;
-  // CHECK: CXXRecordDecl {{.*}} implicit class __layout.CB.5 definition
+  // CHECK: CXXRecordDecl {{.*}} implicit class __layout_CB_5 definition
   // CHECK-NOT: FieldDecl
 }
 
 // check host layout struct with compatible base struct
-// CHECK: HLSLBufferDecl {{.*}} line:141:9 cbuffer CB
+// CHECK: HLSLBufferDecl {{.*}} line:159:9 cbuffer CB
 // CHECK: HLSLResourceClassAttr {{.*}} Implicit CBuffer
 // CHECK: HLSLResourceAttr {{.*}} Implicit CBuffer
 cbuffer CB {
   // CHECK: VarDecl {{.*}} s8 'F'
   F s8;
-  // CHECK: CXXRecordDecl {{.*}} implicit class __layout.F definition
+  // CHECK: CXXRecordDecl {{.*}} implicit referenced class __layout_F 
definition
   // CHECK: public 'A'
-  // CHECK: CXXRecordDecl {{.*}} implicit class __layout.CB.6 definition
-  // CHECK: FieldDecl {{.*}} s8 '__layout.F'
+  // CHECK: CXXRecordDecl {{.*}} implicit referenced class __layout_CB_6 
definition
+  // CHECK: FieldDecl {{.*}} s8 '__layout_F'
 }
+_Static_assert(__builtin_hlsl_is_scalarized_layout_compatible(OneFloat, 
__layout_F), "");
+_Static_assert(__builtin_hlsl_is_scalarized_layout_compatible(OneFloat, 
__layout_CB_6), "");
 
 // anonymous structs
-// CHECK: HLSLBufferDecl {{.*}} line:154:9 cbuffer CB
+// CHECK: HLSLBufferDecl {{.*}} line:174:9 cbuffer CB
 // CHECK: HLSLResourceClassAttr {{.*}} Implicit CBuffer
 // CHECK: HLSLResourceAttr {{.*}} Implicit CBuffer
 cbuffer CB {
@@ -161,23 +181,26 @@ cbuffer CB {
     // CHECK: FieldDecl {{.*}} f 'RWBuffer<float>':'hlsl::RWBuffer<float>'
     RWBuffer<float> f;
   } s9;
-  // CHECK: VarDecl {{.*}} s9 'struct (unnamed struct at 
{{.*}}cbuffer.hlsl:156:3
+  // CHECK: VarDecl {{.*}} s9 'struct (unnamed struct at 
{{.*}}cbuffer.hlsl:176:3
   // CHECK: CXXRecordDecl {{.*}} struct definition
   struct {
-    // CHECK: FieldDecl {{.*}} g 'int'
-    int g;
+    // CHECK: FieldDecl {{.*}} g 'float'
+    float g;
     // CHECK: FieldDecl {{.*}} f 'RWBuffer<float>':'hlsl::RWBuffer<float>'
     RWBuffer<float> f;
   } s10;
-  // CHECK: VarDecl {{.*}} s10 'struct (unnamed struct at 
{{.*}}cbuffer.hlsl:166:3
-  // CHECK: CXXRecordDecl {{.*}} implicit class __layout.anon definition
+  // CHECK: VarDecl {{.*}} s10 'struct (unnamed struct at 
{{.*}}cbuffer.hlsl:186:3
+  // CHECK: CXXRecordDecl {{.*}} implicit referenced class __layout_anon 
definition
   // CHECK: FieldDecl {{.*}} e 'float'
-  // CHECK: CXXRecordDecl {{.*}} implicit class __layout.anon.1 definition
-  // CHECK: FieldDecl {{.*}} g 'int'
-  // CHECK: CXXRecordDecl {{.*}} implicit class __layout.CB.7 definition
-  // CHECK: FieldDecl {{.*}} s9 '__layout.anon'
-  // CHECK: FieldDecl {{.*}} s10 '__layout.anon.1'
+  // CHECK: CXXRecordDecl {{.*}} implicit referenced class __layout_anon_1 
definition
+  // CHECK: FieldDecl {{.*}} g 'float'
+  // CHECK: CXXRecordDecl {{.*}} implicit referenced class __layout_CB_7 
definition
+  // CHECK: FieldDecl {{.*}} s9 '__layout_anon'
+  // CHECK: FieldDecl {{.*}} s10 '__layout_anon_1'
 }
+_Static_assert(__builtin_hlsl_is_scalarized_layout_compatible(OneFloat, 
__layout_anon), "");
+_Static_assert(__builtin_hlsl_is_scalarized_layout_compatible(OneFloat, 
__layout_anon_1), "");
+_Static_assert(__builtin_hlsl_is_scalarized_layout_compatible(TwoFloats, 
__layout_CB_7), "");
 
 // Add uses for the constant buffer declarations so they are not optimized away
 export float foo() {
diff --git a/clang/test/AST/HLSL/pch_hlsl_buffer.hlsl 
b/clang/test/AST/HLSL/pch_hlsl_buffer.hlsl
index 02310c068c166e..3eabbb1f8ae22c 100644
--- a/clang/test/AST/HLSL/pch_hlsl_buffer.hlsl
+++ b/clang/test/AST/HLSL/pch_hlsl_buffer.hlsl
@@ -21,14 +21,14 @@ float foo() {
 // CHECK-NEXT: HLSLResourceClassAttr {{.*}} Implicit CBuffer
 // CHECK-NEXT: HLSLResourceAttr {{.*}} Implicit CBuffer
 // CHECK-NEXT: VarDecl 0x[[A:[0-9a-f]+]] {{.*}} imported used a 'float'
-// CHECK-NEXT: CXXRecordDecl {{.*}} imported implicit <undeserialized 
declarations> class __layout.A definition
+// CHECK-NEXT: CXXRecordDecl {{.*}} imported implicit <undeserialized 
declarations> class __layout_A definition
 // CHECK: FieldDecl {{.*}} imported a 'float'
 
 // CHECK: HLSLBufferDecl {{.*}} line:11:9 imported <undeserialized 
declarations> tbuffer B
 // CHECK-NEXT: HLSLResourceClassAttr {{.*}} Implicit SRV
 // CHECK-NEXT: HLSLResourceAttr {{.*}} Implicit TBuffer
 // CHECK-NEXT: VarDecl 0x[[B:[0-9a-f]+]] {{.*}} imported used b 'float'
-// CHECK-NEXT: CXXRecordDecl 0x{{[0-9a-f]+}} {{.*}} imported implicit 
<undeserialized declarations> class __layout.B definition
+// CHECK-NEXT: CXXRecordDecl 0x{{[0-9a-f]+}} {{.*}} imported implicit 
<undeserialized declarations> class __layout_B definition
 // CHECK: FieldDecl 0x{{[0-9a-f]+}} {{.*}} imported b 'float'
 
 // CHECK-NEXT: FunctionDecl {{.*}} line:15:7 imported foo 'float ()'

>From bbdd56b8338c50efaca278caeefe8a7b2a62f06b Mon Sep 17 00:00:00 2001
From: Helena Kotas <heko...@microsoft.com>
Date: Wed, 22 Jan 2025 12:41:52 -0800
Subject: [PATCH 6/8] code review feedback - use StringRef, update lookup kind

---
 clang/lib/Sema/SemaHLSL.cpp | 23 ++++++++++++-----------
 1 file changed, 12 insertions(+), 11 deletions(-)

diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index 8796848805e110..f8cf6061093c08 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -46,6 +46,9 @@
 using namespace clang;
 using RegisterType = HLSLResourceBindingAttr::RegisterType;
 
+static CXXRecordDecl *createHostLayoutStruct(Sema &S, CXXRecordDecl 
*StructDecl,
+                                             HLSLBufferDecl *BufDecl);
+
 static RegisterType getRegisterType(ResourceClass RC) {
   switch (RC) {
   case ResourceClass::SRV:
@@ -296,7 +299,7 @@ static CXXRecordDecl *findRecordDecl(Sema &S, 
IdentifierInfo *II,
                                      DeclContext *DC) {
   DeclarationNameInfo NameInfo =
       DeclarationNameInfo(DeclarationName(II), SourceLocation());
-  LookupResult R(S, NameInfo, Sema::LookupOrdinaryName);
+  LookupResult R(S, NameInfo, Sema::LookupTagName);
   S.LookupName(R, S.getScopeForContext(DC));
   if (R.isSingleResult())
     return R.getAsSingle<CXXRecordDecl>();
@@ -311,16 +314,16 @@ static IdentifierInfo *getHostLayoutStructName(Sema &S,
                                                bool MustBeUnique,
                                                DeclContext *DC) {
   ASTContext &AST = S.getASTContext();
-  std::string NameBase;
+  StringRef NameBase;
   if (NameBaseII) {
-    NameBase = NameBaseII->getName().str();
+    NameBase = NameBaseII->getName();
   } else {
     // anonymous struct
     NameBase = "anon";
     MustBeUnique = true;
   }
 
-  std::string Name = "__layout_" + NameBase;
+  std::string Name = ("__layout_" + NameBase).str();
   IdentifierInfo *II = &AST.Idents.get(Name, tok::TokenKind::identifier);
   if (!MustBeUnique)
     return II;
@@ -328,7 +331,7 @@ static IdentifierInfo *getHostLayoutStructName(Sema &S,
   unsigned suffix = 0;
   while (true) {
     if (suffix != 0)
-      II = &AST.Idents.get((llvm::Twine(Name) + "_" + Twine(suffix)).str(),
+      II = &AST.Idents.get((Name + "_" + Twine(suffix)).str(),
                            tok::TokenKind::identifier);
     if (!findRecordDecl(S, II, DC))
       return II;
@@ -343,9 +346,6 @@ static bool isResourceRecordType(const Type *Ty) {
   return HLSLAttributedResourceType::findHandleTypeOnResource(Ty) != nullptr;
 }
 
-static CXXRecordDecl *createHostLayoutStruct(Sema &S, CXXRecordDecl 
*StructDecl,
-                                             HLSLBufferDecl *BufDecl);
-
 // Creates a field declaration of given name and type for HLSL buffer layout
 // struct. Returns nullptr if the type cannot be use in HLSL Buffer layout.
 static FieldDecl *createFieldForHostLayoutStruct(Sema &S, const Type *Ty,
@@ -362,10 +362,11 @@ static FieldDecl *createFieldForHostLayoutStruct(Sema &S, 
const Type *Ty,
         return nullptr;
       Ty = RD->getTypeForDecl();
     }
-  } else if (Ty->isConstantArrayType()) {
-    if (isZeroSizedArray(cast<ConstantArrayType>(Ty)))
-      return nullptr;
   }
+  if (Ty->isConstantArrayType() &&
+      isZeroSizedArray(cast<ConstantArrayType>(Ty)))
+    return nullptr;
+
   QualType QT = QualType(Ty, 0);
   ASTContext &AST = S.getASTContext();
   TypeSourceInfo *TSI = AST.getTrivialTypeSourceInfo(QT, SourceLocation());

>From 80fc426305ace181d6ad44cf09e5896592b591c7 Mon Sep 17 00:00:00 2001
From: Helena Kotas <heko...@microsoft.com>
Date: Wed, 22 Jan 2025 23:59:36 -0800
Subject: [PATCH 7/8] Code review feedback - create common function
 isInvalidConstantBufferLeafElementType - create layout structs in the same
 context as the original struct - fix lookup to scan just the first
 non-transparent context - add test case with namespaces

---
 clang/lib/Sema/SemaHLSL.cpp                   | 120 ++++++++++--------
 clang/test/AST/HLSL/cbuffer.hlsl              |  35 ++---
 .../test/AST/HLSL/cbuffer_and_namespaces.hlsl |  98 ++++++++++++++
 3 files changed, 184 insertions(+), 69 deletions(-)
 create mode 100644 clang/test/AST/HLSL/cbuffer_and_namespaces.hlsl

diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index f8cf6061093c08..1a8ae295e8b140 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -15,6 +15,7 @@
 #include "clang/AST/Decl.h"
 #include "clang/AST/DeclBase.h"
 #include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclarationName.h"
 #include "clang/AST/DynamicRecursiveASTVisitor.h"
 #include "clang/AST/Expr.h"
 #include "clang/AST/Type.h"
@@ -46,8 +47,8 @@
 using namespace clang;
 using RegisterType = HLSLResourceBindingAttr::RegisterType;
 
-static CXXRecordDecl *createHostLayoutStruct(Sema &S, CXXRecordDecl 
*StructDecl,
-                                             HLSLBufferDecl *BufDecl);
+static CXXRecordDecl *createHostLayoutStruct(Sema &S,
+                                             CXXRecordDecl *StructDecl);
 
 static RegisterType getRegisterType(ResourceClass RC) {
   switch (RC) {
@@ -268,6 +269,30 @@ static bool isZeroSizedArray(const ConstantArrayType *CAT) 
{
   return CAT != nullptr;
 }
 
+// Returns true if the record type is an HLSL resource class
+static bool isResourceRecordType(const Type *Ty) {
+  return HLSLAttributedResourceType::findHandleTypeOnResource(Ty) != nullptr;
+}
+
+// Returns true if the type is a leaf element type that is not valid to be 
included
+// in HLSL Buffer, such as a resource class, empty struct, zero-sized array,
+// or a builtin intangible type.
+// Returns false it is a valid leaf element type or if it is a record type that
+// needs to be inspected further.
+static bool isInvalidConstantBufferLeafElementType(const Type *Ty) {
+  if (Ty->isRecordType()) {
+    if (isResourceRecordType(Ty) || Ty->getAsCXXRecordDecl()->isEmpty())
+      return true;
+    return false;
+  }
+  if (Ty->isConstantArrayType() &&
+      isZeroSizedArray(cast<ConstantArrayType>(Ty)))
+    return true;
+  if (Ty->isHLSLBuiltinIntangibleType())
+    return true;
+  return false;
+}
+
 // Returns true if the struct contains at least one element that prevents it
 // from being included inside HLSL Buffer as is, such as an intangible type,
 // empty struct, or zero-sized array. If it does, a new implicit layout struct
@@ -279,13 +304,11 @@ static bool requiresImplicitBufferLayoutStructure(const 
CXXRecordDecl *RD) {
   // check fields
   for (const FieldDecl *Field : RD->fields()) {
     QualType Ty = Field->getType();
-    if (Ty->isRecordType()) {
-      if (requiresImplicitBufferLayoutStructure(Ty->getAsCXXRecordDecl()))
-        return true;
-    } else if (Ty->isConstantArrayType()) {
-      if (isZeroSizedArray(cast<ConstantArrayType>(Ty)))
-        return true;
-    }
+    if (isInvalidConstantBufferLeafElementType(Ty.getTypePtr()))
+      return true;
+    if (Ty->isRecordType() &&
+        requiresImplicitBufferLayoutStructure(Ty->getAsCXXRecordDecl()))
+      return true;
   }
   // check bases
   for (const CXXBaseSpecifier &Base : RD->bases())
@@ -295,25 +318,28 @@ static bool requiresImplicitBufferLayoutStructure(const 
CXXRecordDecl *RD) {
   return false;
 }
 
-static CXXRecordDecl *findRecordDecl(Sema &S, IdentifierInfo *II,
-                                     DeclContext *DC) {
-  DeclarationNameInfo NameInfo =
-      DeclarationNameInfo(DeclarationName(II), SourceLocation());
-  LookupResult R(S, NameInfo, Sema::LookupTagName);
-  S.LookupName(R, S.getScopeForContext(DC));
-  if (R.isSingleResult())
-    return R.getAsSingle<CXXRecordDecl>();
-  return nullptr;
+static CXXRecordDecl *findRecordDeclInContext(IdentifierInfo *II,
+                                              DeclContext *DC) {
+  CXXRecordDecl *RD = nullptr;
+  for (NamedDecl *Decl :
+       DC->getNonTransparentContext()->lookup(DeclarationName(II))) {
+    if (CXXRecordDecl *FoundRD = dyn_cast<CXXRecordDecl>(Decl)) {
+      assert(RD == nullptr &&
+             "there should be at most 1 record by a given name in a scope");
+      RD = FoundRD;
+    }
+  }
+  return RD;
 }
 
 // Creates a name for buffer layout struct using the provide name base.
 // If the name must be unique (not previously defined), a suffix is added
 // until a unique name is found.
-static IdentifierInfo *getHostLayoutStructName(Sema &S,
-                                               IdentifierInfo *NameBaseII,
-                                               bool MustBeUnique,
-                                               DeclContext *DC) {
+static IdentifierInfo *getHostLayoutStructName(Sema &S, NamedDecl *BaseDecl,
+                                               bool MustBeUnique) {
   ASTContext &AST = S.getASTContext();
+
+  IdentifierInfo *NameBaseII = BaseDecl->getIdentifier();
   StringRef NameBase;
   if (NameBaseII) {
     NameBase = NameBaseII->getName();
@@ -333,7 +359,7 @@ static IdentifierInfo *getHostLayoutStructName(Sema &S,
     if (suffix != 0)
       II = &AST.Idents.get((Name + "_" + Twine(suffix)).str(),
                            tok::TokenKind::identifier);
-    if (!findRecordDecl(S, II, DC))
+    if (!findRecordDeclInContext(II, BaseDecl->getDeclContext()))
       return II;
     // declaration with that name already exists - increment suffix and try
     // again until unique name is found
@@ -341,31 +367,23 @@ static IdentifierInfo *getHostLayoutStructName(Sema &S,
   };
 }
 
-// Returns true if the record type is an HLSL resource class
-static bool isResourceRecordType(const Type *Ty) {
-  return HLSLAttributedResourceType::findHandleTypeOnResource(Ty) != nullptr;
-}
-
 // Creates a field declaration of given name and type for HLSL buffer layout
 // struct. Returns nullptr if the type cannot be use in HLSL Buffer layout.
 static FieldDecl *createFieldForHostLayoutStruct(Sema &S, const Type *Ty,
                                                  IdentifierInfo *II,
-                                                 CXXRecordDecl *LayoutStruct,
-                                                 HLSLBufferDecl *BufDecl) {
+                                                 CXXRecordDecl *LayoutStruct) {
+  if (isInvalidConstantBufferLeafElementType(Ty))
+    return nullptr;
+
   if (Ty->isRecordType()) {
-    if (isResourceRecordType(Ty))
-      return nullptr;
     CXXRecordDecl *RD = Ty->getAsCXXRecordDecl();
     if (requiresImplicitBufferLayoutStructure(RD)) {
-      RD = createHostLayoutStruct(S, RD, BufDecl);
+      RD = createHostLayoutStruct(S, RD);
       if (!RD)
         return nullptr;
       Ty = RD->getTypeForDecl();
     }
   }
-  if (Ty->isConstantArrayType() &&
-      isZeroSizedArray(cast<ConstantArrayType>(Ty)))
-    return nullptr;
 
   QualType QT = QualType(Ty, 0);
   ASTContext &AST = S.getASTContext();
@@ -384,23 +402,21 @@ static FieldDecl *createFieldForHostLayoutStruct(Sema &S, 
const Type *Ty,
 // - empty structs
 // - zero-sized arrays
 // Returns nullptr if the resulting layout struct would be empty.
-static CXXRecordDecl *createHostLayoutStruct(Sema &S, CXXRecordDecl 
*StructDecl,
-                                             HLSLBufferDecl *BufDecl) {
+static CXXRecordDecl *createHostLayoutStruct(Sema &S,
+                                             CXXRecordDecl *StructDecl) {
   assert(requiresImplicitBufferLayoutStructure(StructDecl) &&
          "struct is already HLSL buffer compatible");
 
   ASTContext &AST = S.getASTContext();
   DeclContext *DC = StructDecl->getDeclContext();
-  IdentifierInfo *II = getHostLayoutStructName(
-      S, StructDecl->getIdentifier(), false, BufDecl->getDeclContext());
+  IdentifierInfo *II = getHostLayoutStructName(S, StructDecl, false);
 
   // reuse existing if the layout struct if it already exists
-  if (CXXRecordDecl *RD = findRecordDecl(S, II, DC))
+  if (CXXRecordDecl *RD = findRecordDeclInContext(II, DC))
     return RD;
 
-  CXXRecordDecl *LS =
-      CXXRecordDecl::Create(AST, TagDecl::TagKind::Class, BufDecl,
-                            SourceLocation(), SourceLocation(), II);
+  CXXRecordDecl *LS = CXXRecordDecl::Create(
+      AST, TagDecl::TagKind::Class, DC, SourceLocation(), SourceLocation(), 
II);
   LS->setImplicit(true);
   LS->startDefinition();
 
@@ -410,7 +426,7 @@ static CXXRecordDecl *createHostLayoutStruct(Sema &S, 
CXXRecordDecl *StructDecl,
     CXXBaseSpecifier Base = *StructDecl->bases_begin();
     CXXRecordDecl *BaseDecl = Base.getType()->getAsCXXRecordDecl();
     if (requiresImplicitBufferLayoutStructure(BaseDecl)) {
-      BaseDecl = createHostLayoutStruct(S, BaseDecl, BufDecl);
+      BaseDecl = createHostLayoutStruct(S, BaseDecl);
       if (BaseDecl) {
         TypeSourceInfo *TSI = AST.getTrivialTypeSourceInfo(
             QualType(BaseDecl->getTypeForDecl(), 0));
@@ -427,15 +443,16 @@ static CXXRecordDecl *createHostLayoutStruct(Sema &S, 
CXXRecordDecl *StructDecl,
   // filter struct fields
   for (const FieldDecl *FD : StructDecl->fields()) {
     const Type *Ty = FD->getType()->getUnqualifiedDesugaredType();
-    if (FieldDecl *NewFD = createFieldForHostLayoutStruct(
-            S, Ty, FD->getIdentifier(), LS, BufDecl))
+    if (FieldDecl *NewFD =
+            createFieldForHostLayoutStruct(S, Ty, FD->getIdentifier(), LS))
       LS->addDecl(NewFD);
   }
   LS->completeDefinition();
 
   if (LS->field_empty() && LS->getNumBases() == 0)
     return nullptr;
-  BufDecl->addDecl(LS);
+
+  DC->addDecl(LS);
   return LS;
 }
 
@@ -449,8 +466,7 @@ static CXXRecordDecl *createHostLayoutStruct(Sema &S, 
CXXRecordDecl *StructDecl,
 // The layour struct will be added to the HLSLBufferDecl declarations.
 void createHostLayoutStructForBuffer(Sema &S, HLSLBufferDecl *BufDecl) {
   ASTContext &AST = S.getASTContext();
-  IdentifierInfo *II = getHostLayoutStructName(S, BufDecl->getIdentifier(),
-                                               true, 
BufDecl->getDeclContext());
+  IdentifierInfo *II = getHostLayoutStructName(S, BufDecl, true);
 
   CXXRecordDecl *LS =
       CXXRecordDecl::Create(AST, TagDecl::TagKind::Class, BufDecl,
@@ -463,8 +479,8 @@ void createHostLayoutStructForBuffer(Sema &S, 
HLSLBufferDecl *BufDecl) {
     if (!VD || VD->getStorageClass() == SC_Static)
       continue;
     const Type *Ty = VD->getType()->getUnqualifiedDesugaredType();
-    if (FieldDecl *FD = createFieldForHostLayoutStruct(
-            S, Ty, VD->getIdentifier(), LS, BufDecl))
+    if (FieldDecl *FD =
+            createFieldForHostLayoutStruct(S, Ty, VD->getIdentifier(), LS))
       LS->addDecl(FD);
   }
   LS->completeDefinition();
diff --git a/clang/test/AST/HLSL/cbuffer.hlsl b/clang/test/AST/HLSL/cbuffer.hlsl
index d78946cd99649b..721abb290f1635 100644
--- a/clang/test/AST/HLSL/cbuffer.hlsl
+++ b/clang/test/AST/HLSL/cbuffer.hlsl
@@ -87,35 +87,36 @@ cbuffer CB {
   B s2;
   // CHECK: VarDecl {{.*}} col:12 s3 'CTypedef':'C
   CTypedef s3;
-  // CHECK: CXXRecordDecl {{.*}} implicit referenced class __layout_B 
definition
-  // CHECK: FieldDecl {{.*}} a 'float'
   // CHECK: CXXRecordDecl {{.*}} implicit referenced class __layout_CB_2 
definition
   // CHECK: FieldDecl {{.*}} s1 'A'
   // CHECK: FieldDecl {{.*}} s2 '__layout_B'
 }
+// CHECK: CXXRecordDecl {{.*}} implicit referenced class __layout_B definition
+// CHECK: FieldDecl {{.*}} a 'float'
+
 _Static_assert(__builtin_hlsl_is_scalarized_layout_compatible(OneFloat, 
__layout_B), "");
 _Static_assert(__builtin_hlsl_is_scalarized_layout_compatible(TwoFloats, 
__layout_CB_2), "");
 
 // check that layout struct is created for D because of its base struct
-// CHECK: HLSLBufferDecl {{.*}} line:103:9 cbuffer CB
+// CHECK: HLSLBufferDecl {{.*}} line:104:9 cbuffer CB
 // CHECK: HLSLResourceClassAttr {{.*}} Implicit CBuffer
 // CHECK: HLSLResourceAttr {{.*}} Implicit CBuffer
 cbuffer CB {
   // CHECK: VarDecl {{.*}} s4 'D'
   D s4;
-  // CHECK: CXXRecordDecl {{.*}} implicit referenced class __layout_D 
definition
-  // CHECK: public '__layout_B'
-  // CHECK: FieldDecl {{.*}} b 'float'
   // CHECK: CXXRecordDecl {{.*}} implicit referenced class __layout_CB_3 
definition
   // CHECK: FieldDecl {{.*}} s4 '__layout_D'
 }
+  // CHECK: CXXRecordDecl {{.*}} implicit referenced class __layout_D 
definition
+  // CHECK: public '__layout_B'
+  // CHECK: FieldDecl {{.*}} b 'float'
 _Static_assert(__builtin_hlsl_is_scalarized_layout_compatible(TwoFloats, 
__layout_D), "");
 _Static_assert(__builtin_hlsl_is_scalarized_layout_compatible(TwoFloats, 
__layout_CB_3), "");
 
 // check that layout struct is created for E because because its base struct
 // is empty and should be eliminated, and BTypedef should reuse the previously
 // defined '__layout_B' 
-// CHECK: HLSLBufferDecl {{.*}} line:121:9 cbuffer CB
+// CHECK: HLSLBufferDecl {{.*}} line:122:9 cbuffer CB
 // CHECK: HLSLResourceClassAttr {{.*}} Implicit CBuffer
 // CHECK: HLSLResourceAttr {{.*}} Implicit CBuffer
 cbuffer CB {
@@ -123,18 +124,18 @@ cbuffer CB {
   E s5;
   // CHECK: VarDecl {{.*}} s6 'BTypedef':'B'
   BTypedef s6;
-  // CHECK: CXXRecordDecl {{.*}} implicit referenced class __layout_E 
definition
-  // CHECK: FieldDecl {{.*}} c 'float'
-  // CHECK-NOT: CXXRecordDecl {{.*}} class __layout_B definition
   // CHECK: CXXRecordDecl {{.*}}  implicit referenced class __layout_CB_4 
definition
   // CHECK: FieldDecl {{.*}} s5 '__layout_E'
   // CHECK: FieldDecl {{.*}} s6 '__layout_B'
 }
+  // CHECK: CXXRecordDecl {{.*}} implicit referenced class __layout_E 
definition
+  // CHECK: FieldDecl {{.*}} c 'float'
+  // CHECK-NOT: CXXRecordDecl {{.*}} class __layout_B definition
 _Static_assert(__builtin_hlsl_is_scalarized_layout_compatible(OneFloat, 
__layout_E), "");
 _Static_assert(__builtin_hlsl_is_scalarized_layout_compatible(TwoFloats, 
__layout_CB_4), "");
 
 // check that this produces empty layout struct
-// CHECK: HLSLBufferDecl {{.*}} line:140:9 cbuffer CB
+// CHECK: HLSLBufferDecl {{.*}} line:141:9 cbuffer CB
 // CHECK: HLSLResourceClassAttr {{.*}} Implicit CBuffer
 // CHECK: HLSLResourceAttr {{.*}} Implicit CBuffer
 cbuffer CB {
@@ -153,22 +154,22 @@ cbuffer CB {
 }
 
 // check host layout struct with compatible base struct
-// CHECK: HLSLBufferDecl {{.*}} line:159:9 cbuffer CB
+// CHECK: HLSLBufferDecl {{.*}} line:160:9 cbuffer CB
 // CHECK: HLSLResourceClassAttr {{.*}} Implicit CBuffer
 // CHECK: HLSLResourceAttr {{.*}} Implicit CBuffer
 cbuffer CB {
   // CHECK: VarDecl {{.*}} s8 'F'
   F s8;
-  // CHECK: CXXRecordDecl {{.*}} implicit referenced class __layout_F 
definition
-  // CHECK: public 'A'
   // CHECK: CXXRecordDecl {{.*}} implicit referenced class __layout_CB_6 
definition
   // CHECK: FieldDecl {{.*}} s8 '__layout_F'
 }
+  // CHECK: CXXRecordDecl {{.*}} implicit referenced class __layout_F 
definition
+  // CHECK: public 'A'
 _Static_assert(__builtin_hlsl_is_scalarized_layout_compatible(OneFloat, 
__layout_F), "");
 _Static_assert(__builtin_hlsl_is_scalarized_layout_compatible(OneFloat, 
__layout_CB_6), "");
 
 // anonymous structs
-// CHECK: HLSLBufferDecl {{.*}} line:174:9 cbuffer CB
+// CHECK: HLSLBufferDecl {{.*}} line:175:9 cbuffer CB
 // CHECK: HLSLResourceClassAttr {{.*}} Implicit CBuffer
 // CHECK: HLSLResourceAttr {{.*}} Implicit CBuffer
 cbuffer CB {
@@ -181,7 +182,7 @@ cbuffer CB {
     // CHECK: FieldDecl {{.*}} f 'RWBuffer<float>':'hlsl::RWBuffer<float>'
     RWBuffer<float> f;
   } s9;
-  // CHECK: VarDecl {{.*}} s9 'struct (unnamed struct at 
{{.*}}cbuffer.hlsl:176:3
+  // CHECK: VarDecl {{.*}} s9 'struct (unnamed struct at 
{{.*}}cbuffer.hlsl:177:3
   // CHECK: CXXRecordDecl {{.*}} struct definition
   struct {
     // CHECK: FieldDecl {{.*}} g 'float'
@@ -189,7 +190,7 @@ cbuffer CB {
     // CHECK: FieldDecl {{.*}} f 'RWBuffer<float>':'hlsl::RWBuffer<float>'
     RWBuffer<float> f;
   } s10;
-  // CHECK: VarDecl {{.*}} s10 'struct (unnamed struct at 
{{.*}}cbuffer.hlsl:186:3
+  // CHECK: VarDecl {{.*}} s10 'struct (unnamed struct at 
{{.*}}cbuffer.hlsl:187:3
   // CHECK: CXXRecordDecl {{.*}} implicit referenced class __layout_anon 
definition
   // CHECK: FieldDecl {{.*}} e 'float'
   // CHECK: CXXRecordDecl {{.*}} implicit referenced class __layout_anon_1 
definition
diff --git a/clang/test/AST/HLSL/cbuffer_and_namespaces.hlsl 
b/clang/test/AST/HLSL/cbuffer_and_namespaces.hlsl
new file mode 100644
index 00000000000000..4b1bbea736f855
--- /dev/null
+++ b/clang/test/AST/HLSL/cbuffer_and_namespaces.hlsl
@@ -0,0 +1,98 @@
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -ast-dump -o - %s | 
FileCheck %s
+
+// CHECK: CXXRecordDecl {{.*}} struct EmptyStruct definition
+struct EmptyStruct {
+};
+
+// CHECK: NamespaceDecl {{.*}} NS1
+namespace NS1 {
+  // CHECK: CXXRecordDecl {{.*}} struct Foo definition
+  struct Foo { 
+    float a;
+    EmptyStruct es;
+  };
+  
+  // CHECK: CXXRecordDecl {{.*}} struct Bar definition
+  struct Bar {
+    // CHECK: CXXRecordDecl {{.*}} struct Foo definition
+    struct Foo {
+      int b;
+      EmptyStruct es;
+    };
+    // CHECK: CXXRecordDecl {{.*}} implicit class __layout_Foo definition
+    // CHECK: FieldDecl {{.*}} b 'int'
+  };
+  // CHECK: CXXRecordDecl {{.*}} implicit class __layout_Foo definition
+  // CHECK: FieldDecl {{.*}} a 'float'
+}
+
+struct Foo {
+  double c;
+  EmptyStruct es;
+};
+
+// CHECK: HLSLBufferDecl {{.*}}  line:37:9 cbuffer CB1
+// CHECK: HLSLResourceClassAttr {{.*}} Implicit CBuffer
+// CHECK: HLSLResourceAttr {{.*}} Implicit CBuffer
+cbuffer CB1 {
+  // CHECK: VarDecl {{.*}} foo1 'Foo'
+  Foo foo1;
+  // CHECK: VarDecl {{.*}} foo2 'NS1::Foo'
+  NS1::Foo foo2;
+  // CHECK: VarDecl {{.*}} foo3 'NS1::Bar::Foo'
+  NS1::Bar::Foo foo3;
+  // CHECK: CXXRecordDecl {{.*}} implicit referenced class __layout_CB1 
definition
+  // CHECK: FieldDecl {{.*}} foo1 '__layout_Foo'
+  // CHECK: FieldDecl {{.*}} foo2 'NS1::__layout_Foo'
+  // CHECK: FieldDecl {{.*}} foo3 'NS1::Bar::__layout_Foo'
+}
+// CHECK: CXXRecordDecl {{.*}} implicit class __layout_Foo definition
+// CHECK: FieldDecl {{.*}} c 'double'
+
+struct CB1ExpectedShape {
+    double a1;
+    float a2;
+    int a;
+};
+_Static_assert(__builtin_hlsl_is_scalarized_layout_compatible(CB1ExpectedShape,
 __layout_CB1), "");
+
+namespace NS2 {
+  struct Foo { 
+    float d[4];
+    EmptyStruct es;
+  };
+  // CHECK: HLSLBufferDecl {{.*}} line:67:11 cbuffer CB2
+  // CHECK: HLSLResourceClassAttr {{.*}} Implicit CBuffer
+  // CHECK: HLSLResourceAttr {{.*}} Implicit CBuffer
+  cbuffer CB2 {
+    // CHECK: VarDecl {{.*}} foo0 '::Foo':'Foo'
+    ::Foo foo0;
+    // CHECK: VarDecl {{.*}} foo1 'Foo':'NS2::Foo'
+    Foo foo1;
+    // CHECK: VarDecl {{.*}} foo2 'NS1::Foo'
+    NS1::Foo foo2;
+    // CHECK: VarDecl {{.*}} foo3 'NS1::Bar::Foo'
+    NS1::Bar::Foo foo3;
+    // CHECK: CXXRecordDecl {{.*}} implicit referenced class __layout_CB2 
definition
+    // CHECK: FieldDecl {{.*}} foo0 '__layout_Foo'
+    // CHECK: FieldDecl {{.*}} foo1 'NS2::__layout_Foo'
+    // CHECK: FieldDecl {{.*}} foo2 'NS1::__layout_Foo'
+    // CHECK: FieldDecl {{.*}} foo3 'NS1::Bar::__layout_Foo'
+  }
+  // CHECK: CXXRecordDecl {{.*}} implicit class __layout_Foo definition
+  // CHECK: FieldDecl {{.*}} d 'float[4]'
+}
+
+struct CB2ExpectedShape {
+    double a1;
+    float d[4];
+    float a2;
+    int a;
+};
+_Static_assert(__builtin_hlsl_is_scalarized_layout_compatible(CB2ExpectedShape,
 NS2::__layout_CB2), "");
+
+// Add uses for the constant buffer declarations so they are not optimized away
+// CHECK: ExportDecl
+export float f() {
+  return foo2.a + NS2::foo2.a;
+}

>From a25ac0a9d2445f0ce64ca9155401dae4c4addfa4 Mon Sep 17 00:00:00 2001
From: Helena Kotas <heko...@microsoft.com>
Date: Thu, 23 Jan 2025 00:12:35 -0800
Subject: [PATCH 8/8] clang-format

---
 clang/lib/Sema/SemaHLSL.cpp | 9 ++++-----
 1 file changed, 4 insertions(+), 5 deletions(-)

diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index 1a8ae295e8b140..6edca32204e7c0 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -274,11 +274,10 @@ static bool isResourceRecordType(const Type *Ty) {
   return HLSLAttributedResourceType::findHandleTypeOnResource(Ty) != nullptr;
 }
 
-// Returns true if the type is a leaf element type that is not valid to be 
included
-// in HLSL Buffer, such as a resource class, empty struct, zero-sized array,
-// or a builtin intangible type.
-// Returns false it is a valid leaf element type or if it is a record type that
-// needs to be inspected further.
+// Returns true if the type is a leaf element type that is not valid to be
+// included in HLSL Buffer, such as a resource class, empty struct, zero-sized
+// array, or a builtin intangible type. Returns false it is a valid leaf 
element
+// type or if it is a record type that needs to be inspected further.
 static bool isInvalidConstantBufferLeafElementType(const Type *Ty) {
   if (Ty->isRecordType()) {
     if (isResourceRecordType(Ty) || Ty->getAsCXXRecordDecl()->isEmpty())

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to