[clang] [llvm] Implement resource binding type prefix mismatch errors (PR #87578)

Joshua Batista via cfe-commits cfe-commits at lists.llvm.org
Thu Jun 20 16:26:49 PDT 2024


https://github.com/bob80905 updated https://github.com/llvm/llvm-project/pull/87578

>From 3960050439964fe3c0536696490b284a6c470cd1 Mon Sep 17 00:00:00 2001
From: Joshua Batista <jbatista at microsoft.com>
Date: Wed, 3 Apr 2024 13:15:59 -0700
Subject: [PATCH 01/15] implement binding type error for t/cbuffers and
 rwbuffers

---
 .../clang/Basic/DiagnosticSemaKinds.td        |  1 +
 clang/lib/Sema/HLSLExternalSemaSource.cpp     | 19 +++--
 clang/lib/Sema/SemaDeclAttr.cpp               | 73 ++++++++++++++++++-
 .../resource_binding_attr_error_mismatch.hlsl | 65 +++++++++++++++++
 4 files changed, 149 insertions(+), 9 deletions(-)
 create mode 100644 clang/test/SemaHLSL/resource_binding_attr_error_mismatch.hlsl

diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 51af81bf1f6fc..9a0946276f80f 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -12149,6 +12149,7 @@ def err_hlsl_missing_semantic_annotation : Error<
 def err_hlsl_init_priority_unsupported : Error<
   "initializer priorities are not supported in HLSL">;
 
+def err_hlsl_mismatching_register_type_and_name: Error<"invalid register name prefix '%0' for register type '%1' (expected '%2')">;
 def err_hlsl_unsupported_register_type : Error<"invalid resource class specifier '%0' used; expected 'b', 's', 't', or 'u'">;
 def err_hlsl_unsupported_register_number : Error<"register number should be an integer">;
 def err_hlsl_expected_space : Error<"invalid space specifier '%0' used; expected 'space' followed by an integer, like space1">;
diff --git a/clang/lib/Sema/HLSLExternalSemaSource.cpp b/clang/lib/Sema/HLSLExternalSemaSource.cpp
index 1a1febf7a3524..479689ec82dce 100644
--- a/clang/lib/Sema/HLSLExternalSemaSource.cpp
+++ b/clang/lib/Sema/HLSLExternalSemaSource.cpp
@@ -119,8 +119,10 @@ struct BuiltinTypeDeclBuilder {
                                                 ResourceKind RK, bool IsROV) {
     if (Record->isCompleteDefinition())
       return *this;
-    Record->addAttr(HLSLResourceAttr::CreateImplicit(Record->getASTContext(),
-                                                     RC, RK, IsROV));
+    HLSLResourceAttr *attr = HLSLResourceAttr::CreateImplicit(
+        Record->getASTContext(), RC, RK, IsROV);
+
+    Record->addAttr(attr);
     return *this;
   }
 
@@ -482,15 +484,18 @@ static BuiltinTypeDeclBuilder setupBufferType(CXXRecordDecl *Decl, Sema &S,
                                               bool IsROV) {
   return BuiltinTypeDeclBuilder(Decl)
       .addHandleMember()
-      .addDefaultHandleConstructor(S, RC)
-      .annotateResourceClass(RC, RK, IsROV);
+      .addDefaultHandleConstructor(S, RC);
 }
 
 void HLSLExternalSemaSource::defineHLSLTypesWithForwardDeclarations() {
   CXXRecordDecl *Decl;
-  Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "RWBuffer")
-             .addSimpleTemplateParams({"element_type"})
-             .Record;
+  Decl =
+      BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "RWBuffer")
+          .addSimpleTemplateParams({"element_type"})
+          .annotateResourceClass(ResourceClass::UAV, ResourceKind::TypedBuffer,
+                                 /*IsROV=*/false)
+          .Record;
+
   onCompletion(Decl, [this](CXXRecordDecl *Decl) {
     setupBufferType(Decl, *SemaPtr, ResourceClass::UAV,
                     ResourceKind::TypedBuffer, /*IsROV=*/false)
diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index f25f3afd0f4af..e720fe56c3ea1 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -7333,12 +7333,12 @@ static void handleHLSLResourceBindingAttr(Sema &S, Decl *D,
   } else {
     Slot = Str;
   }
-
+  QualType Ty = ((clang::ValueDecl *)D)->getType();
   // Validate.
   if (!Slot.empty()) {
     switch (Slot[0]) {
-    case 'u':
     case 'b':
+    case 'u':
     case 's':
     case 't':
       break;
@@ -7367,6 +7367,75 @@ static void handleHLSLResourceBindingAttr(Sema &S, Decl *D,
     return;
   }
 
+  VarDecl *VD = dyn_cast<VarDecl>(D);
+  HLSLBufferDecl *BD = dyn_cast<HLSLBufferDecl>(D);
+
+  if (VD || BD) {
+    llvm::hlsl::ResourceClass RC;
+    std::string varTy = "";
+    if (VD) {
+
+      const Type *Ty = VD->getType()->getPointeeOrArrayElementType();
+      if (!Ty)
+        return;
+      QualType t = ((ElaboratedType *)Ty)->getNamedType();
+      const CXXRecordDecl *RD = Ty->getAsCXXRecordDecl();
+      if (!RD)
+        return;
+
+      if (auto TDecl = dyn_cast<ClassTemplateSpecializationDecl>(RD))
+        RD = TDecl->getSpecializedTemplate()->getTemplatedDecl();
+      RD = RD->getCanonicalDecl();
+      const auto *Attr = RD->getAttr<HLSLResourceAttr>();
+      if (!Attr)
+        return;
+
+      RC = Attr->getResourceClass();
+      varTy = RD->getNameAsString();
+    } else {
+      if (BD->isCBuffer()) {
+        RC = llvm::hlsl::ResourceClass::CBuffer;
+        varTy = "cbuffer";
+      } else {
+        RC = llvm::hlsl::ResourceClass::CBuffer;
+        varTy = "tbuffer";
+      }
+    }
+    switch (RC) {
+    case llvm::hlsl::ResourceClass::SRV: {
+      if (Slot.substr(0, 1) != "t")
+        S.Diag(ArgLoc, diag::err_hlsl_mismatching_register_type_and_name)
+            << Slot.substr(0, 1) << varTy << "t";
+      break;
+    }
+    case llvm::hlsl::ResourceClass::UAV: {
+      if (Slot.substr(0, 1) != "u")
+        S.Diag(ArgLoc, diag::err_hlsl_mismatching_register_type_and_name)
+            << Slot.substr(0, 1) << varTy << "u";
+      break;
+    }
+    case llvm::hlsl::ResourceClass::CBuffer: {
+      if (Slot.substr(0, 1) != "b")
+        S.Diag(ArgLoc, diag::err_hlsl_mismatching_register_type_and_name)
+            << Slot.substr(0, 1) << varTy << "b";
+      break;
+    }
+    case llvm::hlsl::ResourceClass::Sampler: {
+      if (Slot.substr(0, 1) != "s")
+        S.Diag(ArgLoc, diag::err_hlsl_mismatching_register_type_and_name)
+            << Slot.substr(0, 1) << varTy << "s";
+      break;
+    }
+    case llvm::hlsl::ResourceClass::Invalid: {
+      llvm_unreachable("Resource class should be valid.");
+      break;
+    }
+
+    default:
+      break;
+    }
+  }
+
   // FIXME: check reg type match decl. Issue
   // https://github.com/llvm/llvm-project/issues/57886.
   HLSLResourceBindingAttr *NewAttr =
diff --git a/clang/test/SemaHLSL/resource_binding_attr_error_mismatch.hlsl b/clang/test/SemaHLSL/resource_binding_attr_error_mismatch.hlsl
new file mode 100644
index 0000000000000..76dcbd201cbd1
--- /dev/null
+++ b/clang/test/SemaHLSL/resource_binding_attr_error_mismatch.hlsl
@@ -0,0 +1,65 @@
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -x hlsl -o - -fsyntax-only %s -verify
+
+
+// expected-error at +1 {{invalid register name prefix 'b' for register type 'RWBuffer' (expected 'u')}}
+RWBuffer<int> a : register(b2, space1);
+
+// expected-error at +1 {{invalid register name prefix 't' for register type 'RWBuffer' (expected 'u')}}
+RWBuffer<int> b : register(t2, space1);
+
+// NOT YET IMPLEMENTED : {{invalid register name prefix 'u' for register type 'Texture1D' (expected 't')}}
+// NOT YET IMPLEMENTED Texture1D<float> tex : register(u3);
+
+// NOT YET IMPLEMENTED : {{invalid register name prefix 's' for register type 'Texture2D' (expected 't')}}
+// NOT YET IMPLEMENTED Texture2D<float> Texture : register(s0);
+
+// NOT YET IMPLEMENTED : {{invalid register name prefix 'u' for register type 'Texture2DMS' (expected 't')}}
+// NOT YET IMPLEMENTED Texture2DMS<float4, 4> T2DMS_t2 : register(u2)
+
+// NOT YET IMPLEMENTED : {{invalid register name prefix 't' for register type 'RWTexture3D' (expected 'u')}}
+// NOT YET IMPLEMENTED RWTexture3D<float4> RWT3D_u1 : register(t1)
+
+// NOT YET IMPLEMENTED : {{invalid register name prefix 'b' for register type 'Texture2DMS' (expected 't' or 's')}}
+// NOT YET IMPLEMENTED TextureCube TCube_b2 : register(B2);
+
+// NOT YET IMPLEMENTED : {{invalid register name prefix 'b' for register type 'Texture2DMS' (expected 't')}}
+// NOT YET IMPLEMENTED TextureCubeArray TCubeArray_t2 : register(b2);
+
+// NOT YET IMPLEMENTED : {{invalid register name prefix 'b' for register type 'Texture2DMS' (expected 't' or 's')}}
+// NOT YET IMPLEMENTED Texture1DArray T1DArray_t2 : register(b2);
+
+// NOT YET IMPLEMENTED : {{invalid register name prefix 'u' for register type 'Texture2DMS' (expected 't' or 's')}}
+// NOT YET IMPLEMENTED Texture2DArray T2DArray_b2 : register(B2);
+
+// NOT YET IMPLEMENTED : {{invalid register name prefix 'u' for register type 'Texture2DMS' (expected 'b' or 'c' or 'i')}}
+// NOT YET IMPLEMENTED Texture2DMSArray<float4> msTextureArray : register(t2, space2);
+
+// NOT YET IMPLEMENTED : {{invalid register name prefix 'u' for register type 'TCubeArray_f2' (expected 't' or 's')}}
+// NOT YET IMPLEMENTED TextureCubeArray TCubeArray_f2 : register(u2);
+
+// NOT YET IMPLEMENTED : {{invalid register name prefix 'u' for register type 'TypedBuffer' (expected 't')}}
+// NOT YET IMPLEMENTED TypedBuffer tbuf : register(u2);
+
+// NOT YET IMPLEMENTED : {{invalid register name prefix 'u' for register type 'RawBuffer' (expected 't')}}
+// NOT YET IMPLEMENTED RawBuffer rbuf : register(u2);
+
+// NOT YET IMPLEMENTED : {{invalid register name prefix 't' for register type 'StructuredBuffer' (expected 'u')}}
+// NOT YET IMPLEMENTED StructuredBuffer ROVStructuredBuff_t2  : register(T2);
+
+// expected-error at +1 {{invalid register name prefix 's' for register type 'cbuffer' (expected 'b')}}
+cbuffer f : register(s2, space1) {}
+
+// NOT YET IMPLEMENTED : {{invalid register name prefix 't' for register type 'Sampler' (expected 's')}}
+// Can this type just be Sampler instead of SamplerState?
+// NOT YET IMPLEMENTED SamplerState MySampler : register(t3, space1);
+
+// expected-error at +1 {{invalid register name prefix 's' for register type 'tbuffer' (expected 'b')}}
+tbuffer f : register(s2, space1) {}
+
+// NOT YET IMPLEMENTED : RTAccelerationStructure doesn't have any example tests in DXC
+
+// NOT YET IMPLEMENTED : {{invalid register name prefix 'u' for register type 'FeedbackTexture2D' (expected 'b' or 'c' or 'i')}}
+// NOT YET IMPLEMENTED FeedbackTexture2D<float> FBTex2D[3][] : register(u0, space26);
+
+// NOT YET IMPLEMENTED : {{invalid register name prefix 'u' for register type 'FeedbackTexture2DArray' (expected 'b' or 'c' or 'i')}}
+// NOT YET IMPLEMENTED FeedbackTexture2DArray<float> FBTex2DArr[3][2][] : register(u0, space27);

>From c307d0e2950976b1862db2a6d3d0005913da4f55 Mon Sep 17 00:00:00 2001
From: Joshua Batista <jbatista at microsoft.com>
Date: Thu, 4 Apr 2024 14:04:58 -0700
Subject: [PATCH 02/15] adjust switch statement, add empty string test cases

---
 clang/lib/Sema/SemaDeclAttr.cpp                   | 15 +++++----------
 .../resource_binding_attr_error_mismatch.hlsl     |  8 ++++++++
 2 files changed, 13 insertions(+), 10 deletions(-)

diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index e720fe56c3ea1..a2b60efbaf538 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -7403,41 +7403,36 @@ static void handleHLSLResourceBindingAttr(Sema &S, Decl *D,
     }
     switch (RC) {
     case llvm::hlsl::ResourceClass::SRV: {
-      if (Slot.substr(0, 1) != "t")
+      if (Slot[0] != 't')
         S.Diag(ArgLoc, diag::err_hlsl_mismatching_register_type_and_name)
             << Slot.substr(0, 1) << varTy << "t";
       break;
     }
     case llvm::hlsl::ResourceClass::UAV: {
-      if (Slot.substr(0, 1) != "u")
+      if (Slot[0] != 'u')
         S.Diag(ArgLoc, diag::err_hlsl_mismatching_register_type_and_name)
             << Slot.substr(0, 1) << varTy << "u";
       break;
     }
     case llvm::hlsl::ResourceClass::CBuffer: {
-      if (Slot.substr(0, 1) != "b")
+      if (Slot[0] != 'b')
         S.Diag(ArgLoc, diag::err_hlsl_mismatching_register_type_and_name)
             << Slot.substr(0, 1) << varTy << "b";
       break;
     }
     case llvm::hlsl::ResourceClass::Sampler: {
-      if (Slot.substr(0, 1) != "s")
+      if (Slot[0] != 's')
         S.Diag(ArgLoc, diag::err_hlsl_mismatching_register_type_and_name)
             << Slot.substr(0, 1) << varTy << "s";
       break;
     }
-    case llvm::hlsl::ResourceClass::Invalid: {
+    default: {
       llvm_unreachable("Resource class should be valid.");
       break;
     }
-
-    default:
-      break;
     }
   }
 
-  // FIXME: check reg type match decl. Issue
-  // https://github.com/llvm/llvm-project/issues/57886.
   HLSLResourceBindingAttr *NewAttr =
       HLSLResourceBindingAttr::Create(S.getASTContext(), Slot, Space, AL);
   if (NewAttr)
diff --git a/clang/test/SemaHLSL/resource_binding_attr_error_mismatch.hlsl b/clang/test/SemaHLSL/resource_binding_attr_error_mismatch.hlsl
index 76dcbd201cbd1..3bce7a0c290f1 100644
--- a/clang/test/SemaHLSL/resource_binding_attr_error_mismatch.hlsl
+++ b/clang/test/SemaHLSL/resource_binding_attr_error_mismatch.hlsl
@@ -63,3 +63,11 @@ tbuffer f : register(s2, space1) {}
 
 // NOT YET IMPLEMENTED : {{invalid register name prefix 'u' for register type 'FeedbackTexture2DArray' (expected 'b' or 'c' or 'i')}}
 // NOT YET IMPLEMENTED FeedbackTexture2DArray<float> FBTex2DArr[3][2][] : register(u0, space27);
+
+
+// empty binding prefix cases:
+// expected-error at +1 {{expected identifier}}
+RWBuffer<int> c: register();
+
+// expected-error at +1 {{expected identifier}}
+RWBuffer<int> d: register("");

>From 2cde16b4a4a49fecce1bad03b590ba51f2d1fa10 Mon Sep 17 00:00:00 2001
From: Joshua Batista <jbatista at microsoft.com>
Date: Thu, 4 Apr 2024 14:25:36 -0700
Subject: [PATCH 03/15] use invalid case instead of default

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

diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index a2b60efbaf538..01224be123fc5 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -7426,7 +7426,7 @@ static void handleHLSLResourceBindingAttr(Sema &S, Decl *D,
             << Slot.substr(0, 1) << varTy << "s";
       break;
     }
-    default: {
+    case llvm::hlsl::ResourceClass::Invalid: {
       llvm_unreachable("Resource class should be valid.");
       break;
     }

>From c77b3ee1856cf668eb6d430e91abe1c2b6e8ac78 Mon Sep 17 00:00:00 2001
From: Joshua Batista <jbatista at microsoft.com>
Date: Wed, 10 Apr 2024 18:11:47 -0700
Subject: [PATCH 04/15] address part of feedback

---
 clang/lib/Sema/HLSLExternalSemaSource.cpp | 6 ++----
 clang/lib/Sema/SemaDeclAttr.cpp           | 8 ++++----
 2 files changed, 6 insertions(+), 8 deletions(-)

diff --git a/clang/lib/Sema/HLSLExternalSemaSource.cpp b/clang/lib/Sema/HLSLExternalSemaSource.cpp
index 479689ec82dce..fb28fd33d09fd 100644
--- a/clang/lib/Sema/HLSLExternalSemaSource.cpp
+++ b/clang/lib/Sema/HLSLExternalSemaSource.cpp
@@ -119,10 +119,8 @@ struct BuiltinTypeDeclBuilder {
                                                 ResourceKind RK, bool IsROV) {
     if (Record->isCompleteDefinition())
       return *this;
-    HLSLResourceAttr *attr = HLSLResourceAttr::CreateImplicit(
-        Record->getASTContext(), RC, RK, IsROV);
-
-    Record->addAttr(attr);
+    Record->addAttr(HLSLResourceAttr::CreateImplicit(Record->getASTContext(),
+                                                     RC, RK, IsROV));
     return *this;
   }
 
diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index 01224be123fc5..596818f43f472 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -7333,7 +7333,7 @@ static void handleHLSLResourceBindingAttr(Sema &S, Decl *D,
   } else {
     Slot = Str;
   }
-  QualType Ty = ((clang::ValueDecl *)D)->getType();
+
   // Validate.
   if (!Slot.empty()) {
     switch (Slot[0]) {
@@ -7372,13 +7372,13 @@ static void handleHLSLResourceBindingAttr(Sema &S, Decl *D,
 
   if (VD || BD) {
     llvm::hlsl::ResourceClass RC;
-    std::string varTy = "";
+    StringRef varTy = "";
     if (VD) {
 
       const Type *Ty = VD->getType()->getPointeeOrArrayElementType();
       if (!Ty)
         return;
-      QualType t = ((ElaboratedType *)Ty)->getNamedType();
+      QualType t = cast<ElaboratedType>(Ty)->getNamedType();
       const CXXRecordDecl *RD = Ty->getAsCXXRecordDecl();
       if (!RD)
         return;
@@ -7391,7 +7391,7 @@ static void handleHLSLResourceBindingAttr(Sema &S, Decl *D,
         return;
 
       RC = Attr->getResourceClass();
-      varTy = RD->getNameAsString();
+      varTy = RD->getName();
     } else {
       if (BD->isCBuffer()) {
         RC = llvm::hlsl::ResourceClass::CBuffer;

>From 110eef6c6eef34d9266827067825905362d2f44a Mon Sep 17 00:00:00 2001
From: Joshua Batista <jbatista at microsoft.com>
Date: Wed, 17 Apr 2024 19:45:14 -0700
Subject: [PATCH 05/15] address rest of feedback, rename variables, create new
 function

---
 .../clang/Basic/DiagnosticSemaKinds.td        |   2 +-
 clang/lib/Sema/HLSLExternalSemaSource.cpp     |  11 +-
 clang/lib/Sema/SemaDeclAttr.cpp               | 143 ++++++++++--------
 .../test/AST/HLSL/resource_binding_attr.hlsl  |   4 +-
 clang/test/CodeGenHLSL/cbuf.hlsl              |   2 +-
 .../SemaHLSL/resource_binding_attr_error.hlsl |   2 +-
 .../resource_binding_attr_error_mismatch.hlsl |  11 +-
 7 files changed, 93 insertions(+), 82 deletions(-)

diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 9a0946276f80f..b235d2ab858c0 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -12149,7 +12149,7 @@ def err_hlsl_missing_semantic_annotation : Error<
 def err_hlsl_init_priority_unsupported : Error<
   "initializer priorities are not supported in HLSL">;
 
-def err_hlsl_mismatching_register_type_and_name: Error<"invalid register name prefix '%0' for register type '%1' (expected '%2')">;
+def err_hlsl_mismatching_register_type_and_name: Error<"invalid register name prefix '%0' for register type '%1' (expected %select{'t'|'u'|'b'|'s'}2)">;
 def err_hlsl_unsupported_register_type : Error<"invalid resource class specifier '%0' used; expected 'b', 's', 't', or 'u'">;
 def err_hlsl_unsupported_register_number : Error<"register number should be an integer">;
 def err_hlsl_expected_space : Error<"invalid space specifier '%0' used; expected 'space' followed by an integer, like space1">;
diff --git a/clang/lib/Sema/HLSLExternalSemaSource.cpp b/clang/lib/Sema/HLSLExternalSemaSource.cpp
index fb28fd33d09fd..f208cfc0e1c05 100644
--- a/clang/lib/Sema/HLSLExternalSemaSource.cpp
+++ b/clang/lib/Sema/HLSLExternalSemaSource.cpp
@@ -478,8 +478,7 @@ void HLSLExternalSemaSource::defineTrivialHLSLTypes() {
 
 /// Set up common members and attributes for buffer types
 static BuiltinTypeDeclBuilder setupBufferType(CXXRecordDecl *Decl, Sema &S,
-                                              ResourceClass RC, ResourceKind RK,
-                                              bool IsROV) {
+                                              ResourceClass RC) {
   return BuiltinTypeDeclBuilder(Decl)
       .addHandleMember()
       .addDefaultHandleConstructor(S, RC);
@@ -495,8 +494,7 @@ void HLSLExternalSemaSource::defineHLSLTypesWithForwardDeclarations() {
           .Record;
 
   onCompletion(Decl, [this](CXXRecordDecl *Decl) {
-    setupBufferType(Decl, *SemaPtr, ResourceClass::UAV,
-                    ResourceKind::TypedBuffer, /*IsROV=*/false)
+    setupBufferType(Decl, *SemaPtr, ResourceClass::UAV)
         .addArraySubscriptOperators()
         .completeDefinition();
   });
@@ -504,10 +502,11 @@ void HLSLExternalSemaSource::defineHLSLTypesWithForwardDeclarations() {
   Decl =
       BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "RasterizerOrderedBuffer")
           .addSimpleTemplateParams({"element_type"})
+          .annotateResourceClass(ResourceClass::UAV, ResourceKind::TypedBuffer,
+                                 /*IsROV=*/true)
           .Record;
   onCompletion(Decl, [this](CXXRecordDecl *Decl) {
-    setupBufferType(Decl, *SemaPtr, ResourceClass::UAV,
-                    ResourceKind::TypedBuffer, /*IsROV=*/true)
+    setupBufferType(Decl, *SemaPtr, ResourceClass::UAV)
         .addArraySubscriptOperators()
         .completeDefinition();
   });
diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index 596818f43f472..653e827f7487f 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -7303,6 +7303,81 @@ Sema::mergeHLSLShaderAttr(Decl *D, const AttributeCommonInfo &AL,
   return HLSLShaderAttr::Create(Context, ShaderType, AL);
 }
 
+static void DiagnoseHLSLResourceRegType(Sema &S, SourceLocation &ArgLoc,
+                                        Decl *D, StringRef &Slot) {
+  // Samplers, UAVs, and SRVs are VarDecl types
+  VarDecl *SamplerUAVOrSRV = dyn_cast<VarDecl>(D);
+  // Cbuffers and Tbuffers are HLSLBufferDecl types
+  HLSLBufferDecl *CBufferOrTBuffer = dyn_cast<HLSLBufferDecl>(D);
+  if (!SamplerUAVOrSRV && !CBufferOrTBuffer)
+    return;
+
+  llvm::hlsl::ResourceClass DeclResourceClass;
+  StringRef varTy = "";
+  if (SamplerUAVOrSRV) {
+    const Type *Ty = SamplerUAVOrSRV->getType()->getPointeeOrArrayElementType();
+    if (!Ty)
+      llvm_unreachable("Resource class should have an element type.");
+
+    const CXXRecordDecl *TheRecordDecl = Ty->getAsCXXRecordDecl();
+    if (!TheRecordDecl)
+      llvm_unreachable(
+          "Resource class should have a resource type declaration.");
+
+    if (auto TDecl = dyn_cast<ClassTemplateSpecializationDecl>(TheRecordDecl))
+      TheRecordDecl = TDecl->getSpecializedTemplate()->getTemplatedDecl();
+    TheRecordDecl = TheRecordDecl->getCanonicalDecl();
+    const auto *Attr = TheRecordDecl->getAttr<HLSLResourceAttr>();
+    if (!Attr)
+      llvm_unreachable("Resource class should have a resource attribute.");
+
+    DeclResourceClass = Attr->getResourceClass();
+    varTy = TheRecordDecl->getName();
+  } else {
+    if (CBufferOrTBuffer->isCBuffer()) {
+      DeclResourceClass = llvm::hlsl::ResourceClass::CBuffer;
+      varTy = "cbuffer";
+    } else {
+      DeclResourceClass = llvm::hlsl::ResourceClass::CBuffer;
+      varTy = "tbuffer";
+    }
+  }
+  switch (DeclResourceClass) {
+  case llvm::hlsl::ResourceClass::SRV: {
+    if (Slot[0] != 't')
+      S.Diag(ArgLoc, diag::err_hlsl_mismatching_register_type_and_name)
+          << Slot.substr(0, 1) << varTy
+          << (unsigned)llvm::hlsl::ResourceClass::SRV;
+    break;
+  }
+  case llvm::hlsl::ResourceClass::UAV: {
+    if (Slot[0] != 'u')
+      S.Diag(ArgLoc, diag::err_hlsl_mismatching_register_type_and_name)
+          << Slot.substr(0, 1) << varTy
+          << (unsigned)llvm::hlsl::ResourceClass::UAV;
+    break;
+  }
+  case llvm::hlsl::ResourceClass::CBuffer: {
+    if (Slot[0] != 'b')
+      S.Diag(ArgLoc, diag::err_hlsl_mismatching_register_type_and_name)
+          << Slot.substr(0, 1) << varTy
+          << (unsigned)llvm::hlsl::ResourceClass::CBuffer;
+    break;
+  }
+  case llvm::hlsl::ResourceClass::Sampler: {
+    if (Slot[0] != 's')
+      S.Diag(ArgLoc, diag::err_hlsl_mismatching_register_type_and_name)
+          << Slot.substr(0, 1) << varTy
+          << (unsigned)llvm::hlsl::ResourceClass::Sampler;
+    break;
+  }
+  case llvm::hlsl::ResourceClass::Invalid: {
+    llvm_unreachable("Resource class should be valid.");
+    break;
+  }
+  }
+}
+
 static void handleHLSLResourceBindingAttr(Sema &S, Decl *D,
                                           const ParsedAttr &AL) {
   StringRef Space = "space0";
@@ -7337,8 +7412,8 @@ static void handleHLSLResourceBindingAttr(Sema &S, Decl *D,
   // Validate.
   if (!Slot.empty()) {
     switch (Slot[0]) {
-    case 'b':
     case 'u':
+    case 'b':
     case 's':
     case 't':
       break;
@@ -7367,71 +7442,7 @@ static void handleHLSLResourceBindingAttr(Sema &S, Decl *D,
     return;
   }
 
-  VarDecl *VD = dyn_cast<VarDecl>(D);
-  HLSLBufferDecl *BD = dyn_cast<HLSLBufferDecl>(D);
-
-  if (VD || BD) {
-    llvm::hlsl::ResourceClass RC;
-    StringRef varTy = "";
-    if (VD) {
-
-      const Type *Ty = VD->getType()->getPointeeOrArrayElementType();
-      if (!Ty)
-        return;
-      QualType t = cast<ElaboratedType>(Ty)->getNamedType();
-      const CXXRecordDecl *RD = Ty->getAsCXXRecordDecl();
-      if (!RD)
-        return;
-
-      if (auto TDecl = dyn_cast<ClassTemplateSpecializationDecl>(RD))
-        RD = TDecl->getSpecializedTemplate()->getTemplatedDecl();
-      RD = RD->getCanonicalDecl();
-      const auto *Attr = RD->getAttr<HLSLResourceAttr>();
-      if (!Attr)
-        return;
-
-      RC = Attr->getResourceClass();
-      varTy = RD->getName();
-    } else {
-      if (BD->isCBuffer()) {
-        RC = llvm::hlsl::ResourceClass::CBuffer;
-        varTy = "cbuffer";
-      } else {
-        RC = llvm::hlsl::ResourceClass::CBuffer;
-        varTy = "tbuffer";
-      }
-    }
-    switch (RC) {
-    case llvm::hlsl::ResourceClass::SRV: {
-      if (Slot[0] != 't')
-        S.Diag(ArgLoc, diag::err_hlsl_mismatching_register_type_and_name)
-            << Slot.substr(0, 1) << varTy << "t";
-      break;
-    }
-    case llvm::hlsl::ResourceClass::UAV: {
-      if (Slot[0] != 'u')
-        S.Diag(ArgLoc, diag::err_hlsl_mismatching_register_type_and_name)
-            << Slot.substr(0, 1) << varTy << "u";
-      break;
-    }
-    case llvm::hlsl::ResourceClass::CBuffer: {
-      if (Slot[0] != 'b')
-        S.Diag(ArgLoc, diag::err_hlsl_mismatching_register_type_and_name)
-            << Slot.substr(0, 1) << varTy << "b";
-      break;
-    }
-    case llvm::hlsl::ResourceClass::Sampler: {
-      if (Slot[0] != 's')
-        S.Diag(ArgLoc, diag::err_hlsl_mismatching_register_type_and_name)
-            << Slot.substr(0, 1) << varTy << "s";
-      break;
-    }
-    case llvm::hlsl::ResourceClass::Invalid: {
-      llvm_unreachable("Resource class should be valid.");
-      break;
-    }
-    }
-  }
+  DiagnoseHLSLResourceRegType(S, ArgLoc, D, Slot);
 
   HLSLResourceBindingAttr *NewAttr =
       HLSLResourceBindingAttr::Create(S.getASTContext(), Slot, Space, AL);
diff --git a/clang/test/AST/HLSL/resource_binding_attr.hlsl b/clang/test/AST/HLSL/resource_binding_attr.hlsl
index 71900f2dbda55..696c563786277 100644
--- a/clang/test/AST/HLSL/resource_binding_attr.hlsl
+++ b/clang/test/AST/HLSL/resource_binding_attr.hlsl
@@ -8,9 +8,9 @@ cbuffer CB : register(b3, space2) {
 }
 
 // CHECK:HLSLBufferDecl 0x[[TB:[0-9a-f]+]] {{.*}} line:13:9 tbuffer TB
-// CHECK-NEXT:HLSLResourceBindingAttr 0x{{[0-9a-f]+}} <col:14> "t2" "space1"
+// CHECK-NEXT:HLSLResourceBindingAttr 0x{{[0-9a-f]+}} <col:14> "b2" "space1"
 // CHECK-NEXT:VarDecl 0x[[B:[0-9a-f]+]] {{.*}} col:9 used b 'float'
-tbuffer TB : register(t2, space1) {
+tbuffer TB : register(b2, space1) {
   float b;
 }
 
diff --git a/clang/test/CodeGenHLSL/cbuf.hlsl b/clang/test/CodeGenHLSL/cbuf.hlsl
index dc2a6aaa8f433..a4e817890cd95 100644
--- a/clang/test/CodeGenHLSL/cbuf.hlsl
+++ b/clang/test/CodeGenHLSL/cbuf.hlsl
@@ -9,7 +9,7 @@ cbuffer A : register(b0, space2) {
 }
 
 // CHECK: @[[TB:.+]] = external constant { float, double }
-tbuffer A : register(t2, space1) {
+tbuffer A : register(b2, space1) {
   float c;
   double d;
 }
diff --git a/clang/test/SemaHLSL/resource_binding_attr_error.hlsl b/clang/test/SemaHLSL/resource_binding_attr_error.hlsl
index 95774472aaea0..42c9e942bb1a5 100644
--- a/clang/test/SemaHLSL/resource_binding_attr_error.hlsl
+++ b/clang/test/SemaHLSL/resource_binding_attr_error.hlsl
@@ -45,7 +45,7 @@ void foo2() {
   extern RWBuffer<float> U2 : register(u5);
 }
 // FIXME: expect-error once fix https://github.com/llvm/llvm-project/issues/57886.
-float b : register(u0, space1);
+// float b : register(u0, space1) {}
 
 // expected-warning at +1 {{'register' attribute only applies to cbuffer/tbuffer and external global variables}}
 void bar(RWBuffer<float> U : register(u3)) {
diff --git a/clang/test/SemaHLSL/resource_binding_attr_error_mismatch.hlsl b/clang/test/SemaHLSL/resource_binding_attr_error_mismatch.hlsl
index 3bce7a0c290f1..8544a2a37949b 100644
--- a/clang/test/SemaHLSL/resource_binding_attr_error_mismatch.hlsl
+++ b/clang/test/SemaHLSL/resource_binding_attr_error_mismatch.hlsl
@@ -1,11 +1,12 @@
 // RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -x hlsl -o - -fsyntax-only %s -verify
 
+// the below will cause an llvm unreachable, because RWBuffers don't have resource attributes yet
+// NOT YET IMPLEMENTED : {{invalid register name prefix 'b' for register type 'RWBuffer' (expected 'u')}}
+// NOT YET IMPLEMENTED RWBuffer<int> a : register(b2, space1);
 
-// expected-error at +1 {{invalid register name prefix 'b' for register type 'RWBuffer' (expected 'u')}}
-RWBuffer<int> a : register(b2, space1);
-
-// expected-error at +1 {{invalid register name prefix 't' for register type 'RWBuffer' (expected 'u')}}
-RWBuffer<int> b : register(t2, space1);
+// the below will cause an llvm unreachable, because RWBuffers don't have resource attributes yet
+// NOT YET IMPLEMENTED : {{invalid register name prefix 't' for register type 'RWBuffer' (expected 'u')}}
+// NOT YET IMPLEMENTED RWBuffer<int> b : register(t2, space1);
 
 // NOT YET IMPLEMENTED : {{invalid register name prefix 'u' for register type 'Texture1D' (expected 't')}}
 // NOT YET IMPLEMENTED Texture1D<float> tex : register(u3);

>From 1a9ea6c1c4792c27f8da401e76ac21909517cee1 Mon Sep 17 00:00:00 2001
From: Joshua Batista <jbatista at microsoft.com>
Date: Thu, 18 Apr 2024 18:46:23 -0700
Subject: [PATCH 06/15] remove unneeded function

---
 clang/lib/Sema/SemaDeclAttr.cpp | 13 -------------
 1 file changed, 13 deletions(-)

diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index 7424f593f8411..f8ff4515d2a26 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -7334,19 +7334,6 @@ static void handleHLSLShaderAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
     D->addAttr(NewAttr);
 }
 
-HLSLShaderAttr *
-Sema::mergeHLSLShaderAttr(Decl *D, const AttributeCommonInfo &AL,
-                          HLSLShaderAttr::ShaderType ShaderType) {
-  if (HLSLShaderAttr *NT = D->getAttr<HLSLShaderAttr>()) {
-    if (NT->getType() != ShaderType) {
-      Diag(NT->getLocation(), diag::err_hlsl_attribute_param_mismatch) << AL;
-      Diag(AL.getLoc(), diag::note_conflicting_attribute);
-    }
-    return nullptr;
-  }
-  return HLSLShaderAttr::Create(Context, ShaderType, AL);
-}
-
 static void DiagnoseHLSLResourceRegType(Sema &S, SourceLocation &ArgLoc,
                                         Decl *D, StringRef &Slot) {
   // Samplers, UAVs, and SRVs are VarDecl types

>From f985ab69433f82610576a1e8b98a09077c78a48c Mon Sep 17 00:00:00 2001
From: Joshua Batista <jbatista at microsoft.com>
Date: Mon, 22 Apr 2024 10:30:09 -0700
Subject: [PATCH 07/15] format

---
 clang/lib/Serialization/ASTWriter.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp
index 2eb4adac53de2..3aaad2381e36b 100644
--- a/clang/lib/Serialization/ASTWriter.cpp
+++ b/clang/lib/Serialization/ASTWriter.cpp
@@ -5014,7 +5014,7 @@ void ASTWriter::WriteSpecialDeclRecords(Sema &SemaRef) {
 
   if (!ModularCodegenDecls.empty())
     Stream.EmitRecord(MODULAR_CODEGEN_DECLS, ModularCodegenDecls);
-  
+
   // Write the record containing tentative definitions.
   RecordData TentativeDefinitions;
   AddLazyVectorEmiitedDecls(*this, SemaRef.TentativeDefinitions,
@@ -5135,7 +5135,7 @@ void ASTWriter::WriteSpecialDeclRecords(Sema &SemaRef) {
   }
   if (!UndefinedButUsed.empty())
     Stream.EmitRecord(UNDEFINED_BUT_USED, UndefinedButUsed);
-  
+
   // Write all delete-expressions that we would like to
   // analyze later in AST.
   RecordData DeleteExprsToAnalyze;

>From 3b2afe7c5282e16604d3ac05f6b25075cbfde4b8 Mon Sep 17 00:00:00 2001
From: Joshua Batista <jbatista at microsoft.com>
Date: Tue, 23 Apr 2024 16:00:22 -0700
Subject: [PATCH 08/15] address all of Justin and Xiang's feedback

---
 .../clang/Basic/DiagnosticSemaKinds.td        |  3 +-
 clang/lib/Sema/HLSLExternalSemaSource.cpp     |  8 ++--
 clang/lib/Sema/SemaDeclAttr.cpp               | 47 +++++++++++++------
 .../test/AST/HLSL/resource_binding_attr.hlsl  |  4 +-
 clang/test/CodeGenHLSL/cbuf.hlsl              |  2 +-
 .../SemaHLSL/resource_binding_attr_error.hlsl |  4 +-
 .../resource_binding_attr_error_mismatch.hlsl | 12 ++---
 .../include/llvm/Frontend/HLSL/HLSLResource.h |  1 +
 8 files changed, 51 insertions(+), 30 deletions(-)

diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 3654dccfea978..de940625b44b4 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -12154,7 +12154,8 @@ def err_hlsl_missing_semantic_annotation : Error<
 def err_hlsl_init_priority_unsupported : Error<
   "initializer priorities are not supported in HLSL">;
 
-def err_hlsl_mismatching_register_type_and_name: Error<"invalid register name prefix '%0' for register type '%1' (expected %select{'t'|'u'|'b'|'s'}2)">;
+def err_hlsl_mismatching_register_resource_type_and_name: Error<"invalid register name prefix '%0' for register resource type '%1' (expected %select{'t'|'u'|'b'|'t'|'s'}2)">;
+def err_hlsl_mismatching_register_builtin_type_and_name: Error<"invalid register name prefix '%0' for '%1' (expected %2)">;
 def err_hlsl_unsupported_register_type : Error<"invalid resource class specifier '%0' used; expected 'b', 's', 't', or 'u'">;
 def err_hlsl_unsupported_register_number : Error<"register number should be an integer">;
 def err_hlsl_expected_space : Error<"invalid space specifier '%0' used; expected 'space' followed by an integer, like space1">;
diff --git a/clang/lib/Sema/HLSLExternalSemaSource.cpp b/clang/lib/Sema/HLSLExternalSemaSource.cpp
index f208cfc0e1c05..b9a6a5baefd25 100644
--- a/clang/lib/Sema/HLSLExternalSemaSource.cpp
+++ b/clang/lib/Sema/HLSLExternalSemaSource.cpp
@@ -477,8 +477,8 @@ void HLSLExternalSemaSource::defineTrivialHLSLTypes() {
 }
 
 /// Set up common members and attributes for buffer types
-static BuiltinTypeDeclBuilder setupBufferType(CXXRecordDecl *Decl, Sema &S,
-                                              ResourceClass RC) {
+static BuiltinTypeDeclBuilder setupBufferHandle(CXXRecordDecl *Decl, Sema &S,
+                                                ResourceClass RC) {
   return BuiltinTypeDeclBuilder(Decl)
       .addHandleMember()
       .addDefaultHandleConstructor(S, RC);
@@ -494,7 +494,7 @@ void HLSLExternalSemaSource::defineHLSLTypesWithForwardDeclarations() {
           .Record;
 
   onCompletion(Decl, [this](CXXRecordDecl *Decl) {
-    setupBufferType(Decl, *SemaPtr, ResourceClass::UAV)
+    setupBufferHandle(Decl, *SemaPtr, ResourceClass::UAV)
         .addArraySubscriptOperators()
         .completeDefinition();
   });
@@ -506,7 +506,7 @@ void HLSLExternalSemaSource::defineHLSLTypesWithForwardDeclarations() {
                                  /*IsROV=*/true)
           .Record;
   onCompletion(Decl, [this](CXXRecordDecl *Decl) {
-    setupBufferType(Decl, *SemaPtr, ResourceClass::UAV)
+    setupBufferHandle(Decl, *SemaPtr, ResourceClass::UAV)
         .addArraySubscriptOperators()
         .completeDefinition();
   });
diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index f8ff4515d2a26..7095825c7d842 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -7344,11 +7344,23 @@ static void DiagnoseHLSLResourceRegType(Sema &S, SourceLocation &ArgLoc,
     return;
 
   llvm::hlsl::ResourceClass DeclResourceClass;
-  StringRef varTy = "";
+  StringRef VarTy = "";
   if (SamplerUAVOrSRV) {
     const Type *Ty = SamplerUAVOrSRV->getType()->getPointeeOrArrayElementType();
     if (!Ty)
-      llvm_unreachable("Resource class should have an element type.");
+      llvm_unreachable("Resource class must have an element type.");
+
+    if (const BuiltinType *BTy = dyn_cast<BuiltinType>(Ty)) {
+      QualType QT = SamplerUAVOrSRV->getType();
+      PrintingPolicy PP = S.getPrintingPolicy();
+      std::string typestr = QualType::getAsString(QT.split(), PP);
+
+      if (Slot[0] != 'b' && Slot[0] != 'c' && Slot[0] != 'i')
+        S.Diag(ArgLoc,
+               diag::err_hlsl_mismatching_register_builtin_type_and_name)
+            << Slot.substr(0, 1) << typestr << "'b, c, or i";
+      return;
+    }
 
     const CXXRecordDecl *TheRecordDecl = Ty->getAsCXXRecordDecl();
     if (!TheRecordDecl)
@@ -7363,42 +7375,49 @@ static void DiagnoseHLSLResourceRegType(Sema &S, SourceLocation &ArgLoc,
       llvm_unreachable("Resource class should have a resource attribute.");
 
     DeclResourceClass = Attr->getResourceClass();
-    varTy = TheRecordDecl->getName();
+    VarTy = TheRecordDecl->getName();
   } else {
     if (CBufferOrTBuffer->isCBuffer()) {
       DeclResourceClass = llvm::hlsl::ResourceClass::CBuffer;
-      varTy = "cbuffer";
+      VarTy = "cbuffer";
     } else {
-      DeclResourceClass = llvm::hlsl::ResourceClass::CBuffer;
-      varTy = "tbuffer";
+      DeclResourceClass = llvm::hlsl::ResourceClass::TBuffer;
+      VarTy = "tbuffer";
     }
   }
   switch (DeclResourceClass) {
   case llvm::hlsl::ResourceClass::SRV: {
     if (Slot[0] != 't')
-      S.Diag(ArgLoc, diag::err_hlsl_mismatching_register_type_and_name)
-          << Slot.substr(0, 1) << varTy
+      S.Diag(ArgLoc, diag::err_hlsl_mismatching_register_resource_type_and_name)
+          << Slot.substr(0, 1) << VarTy
           << (unsigned)llvm::hlsl::ResourceClass::SRV;
     break;
   }
   case llvm::hlsl::ResourceClass::UAV: {
     if (Slot[0] != 'u')
-      S.Diag(ArgLoc, diag::err_hlsl_mismatching_register_type_and_name)
-          << Slot.substr(0, 1) << varTy
+      S.Diag(ArgLoc, diag::err_hlsl_mismatching_register_resource_type_and_name)
+          << Slot.substr(0, 1) << VarTy
           << (unsigned)llvm::hlsl::ResourceClass::UAV;
     break;
   }
   case llvm::hlsl::ResourceClass::CBuffer: {
     if (Slot[0] != 'b')
-      S.Diag(ArgLoc, diag::err_hlsl_mismatching_register_type_and_name)
-          << Slot.substr(0, 1) << varTy
+      S.Diag(ArgLoc, diag::err_hlsl_mismatching_register_resource_type_and_name)
+          << Slot.substr(0, 1) << VarTy
           << (unsigned)llvm::hlsl::ResourceClass::CBuffer;
     break;
   }
+  case llvm::hlsl::ResourceClass::TBuffer: {
+    if (Slot[0] != 't')
+      S.Diag(ArgLoc, diag::err_hlsl_mismatching_register_resource_type_and_name)
+          << Slot.substr(0, 1) << VarTy
+          << (unsigned)llvm::hlsl::ResourceClass::TBuffer;
+    break;
+  }
   case llvm::hlsl::ResourceClass::Sampler: {
     if (Slot[0] != 's')
-      S.Diag(ArgLoc, diag::err_hlsl_mismatching_register_type_and_name)
-          << Slot.substr(0, 1) << varTy
+      S.Diag(ArgLoc, diag::err_hlsl_mismatching_register_resource_type_and_name)
+          << Slot.substr(0, 1) << VarTy
           << (unsigned)llvm::hlsl::ResourceClass::Sampler;
     break;
   }
diff --git a/clang/test/AST/HLSL/resource_binding_attr.hlsl b/clang/test/AST/HLSL/resource_binding_attr.hlsl
index 696c563786277..71900f2dbda55 100644
--- a/clang/test/AST/HLSL/resource_binding_attr.hlsl
+++ b/clang/test/AST/HLSL/resource_binding_attr.hlsl
@@ -8,9 +8,9 @@ cbuffer CB : register(b3, space2) {
 }
 
 // CHECK:HLSLBufferDecl 0x[[TB:[0-9a-f]+]] {{.*}} line:13:9 tbuffer TB
-// CHECK-NEXT:HLSLResourceBindingAttr 0x{{[0-9a-f]+}} <col:14> "b2" "space1"
+// CHECK-NEXT:HLSLResourceBindingAttr 0x{{[0-9a-f]+}} <col:14> "t2" "space1"
 // CHECK-NEXT:VarDecl 0x[[B:[0-9a-f]+]] {{.*}} col:9 used b 'float'
-tbuffer TB : register(b2, space1) {
+tbuffer TB : register(t2, space1) {
   float b;
 }
 
diff --git a/clang/test/CodeGenHLSL/cbuf.hlsl b/clang/test/CodeGenHLSL/cbuf.hlsl
index a4e817890cd95..dc2a6aaa8f433 100644
--- a/clang/test/CodeGenHLSL/cbuf.hlsl
+++ b/clang/test/CodeGenHLSL/cbuf.hlsl
@@ -9,7 +9,7 @@ cbuffer A : register(b0, space2) {
 }
 
 // CHECK: @[[TB:.+]] = external constant { float, double }
-tbuffer A : register(b2, space1) {
+tbuffer A : register(t2, space1) {
   float c;
   double d;
 }
diff --git a/clang/test/SemaHLSL/resource_binding_attr_error.hlsl b/clang/test/SemaHLSL/resource_binding_attr_error.hlsl
index 42c9e942bb1a5..c2e09c116654f 100644
--- a/clang/test/SemaHLSL/resource_binding_attr_error.hlsl
+++ b/clang/test/SemaHLSL/resource_binding_attr_error.hlsl
@@ -44,8 +44,8 @@ void foo2() {
   // expected-warning at +1 {{'register' attribute only applies to cbuffer/tbuffer and external global variables}}
   extern RWBuffer<float> U2 : register(u5);
 }
-// FIXME: expect-error once fix https://github.com/llvm/llvm-project/issues/57886.
-// float b : register(u0, space1) {}
+// expected-error at +1 {{invalid register name prefix 'u' for 'float' (expected 'b, c, or i)}}
+float b : register(u0, space1);
 
 // expected-warning at +1 {{'register' attribute only applies to cbuffer/tbuffer and external global variables}}
 void bar(RWBuffer<float> U : register(u3)) {
diff --git a/clang/test/SemaHLSL/resource_binding_attr_error_mismatch.hlsl b/clang/test/SemaHLSL/resource_binding_attr_error_mismatch.hlsl
index 8544a2a37949b..4bff910c0a7a4 100644
--- a/clang/test/SemaHLSL/resource_binding_attr_error_mismatch.hlsl
+++ b/clang/test/SemaHLSL/resource_binding_attr_error_mismatch.hlsl
@@ -1,12 +1,12 @@
 // RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -x hlsl -o - -fsyntax-only %s -verify
 
 // the below will cause an llvm unreachable, because RWBuffers don't have resource attributes yet
-// NOT YET IMPLEMENTED : {{invalid register name prefix 'b' for register type 'RWBuffer' (expected 'u')}}
-// NOT YET IMPLEMENTED RWBuffer<int> a : register(b2, space1);
+// expected-error at +1  {{invalid register name prefix 'b' for register resource type 'RWBuffer' (expected 'u')}}
+RWBuffer<int> a : register(b2, space1);
 
 // the below will cause an llvm unreachable, because RWBuffers don't have resource attributes yet
-// NOT YET IMPLEMENTED : {{invalid register name prefix 't' for register type 'RWBuffer' (expected 'u')}}
-// NOT YET IMPLEMENTED RWBuffer<int> b : register(t2, space1);
+// expected-error at +1  {{invalid register name prefix 't' for register resource type 'RWBuffer' (expected 'u')}}
+RWBuffer<int> b : register(t2, space1);
 
 // NOT YET IMPLEMENTED : {{invalid register name prefix 'u' for register type 'Texture1D' (expected 't')}}
 // NOT YET IMPLEMENTED Texture1D<float> tex : register(u3);
@@ -47,14 +47,14 @@
 // NOT YET IMPLEMENTED : {{invalid register name prefix 't' for register type 'StructuredBuffer' (expected 'u')}}
 // NOT YET IMPLEMENTED StructuredBuffer ROVStructuredBuff_t2  : register(T2);
 
-// expected-error at +1 {{invalid register name prefix 's' for register type 'cbuffer' (expected 'b')}}
+// expected-error at +1 {{invalid register name prefix 's' for register resource type 'cbuffer' (expected 'b')}}
 cbuffer f : register(s2, space1) {}
 
 // NOT YET IMPLEMENTED : {{invalid register name prefix 't' for register type 'Sampler' (expected 's')}}
 // Can this type just be Sampler instead of SamplerState?
 // NOT YET IMPLEMENTED SamplerState MySampler : register(t3, space1);
 
-// expected-error at +1 {{invalid register name prefix 's' for register type 'tbuffer' (expected 'b')}}
+// expected-error at +1 {{invalid register name prefix 's' for register resource type 'tbuffer' (expected 't')}}
 tbuffer f : register(s2, space1) {}
 
 // NOT YET IMPLEMENTED : RTAccelerationStructure doesn't have any example tests in DXC
diff --git a/llvm/include/llvm/Frontend/HLSL/HLSLResource.h b/llvm/include/llvm/Frontend/HLSL/HLSLResource.h
index edfcbda0a3bb3..61ec920b76092 100644
--- a/llvm/include/llvm/Frontend/HLSL/HLSLResource.h
+++ b/llvm/include/llvm/Frontend/HLSL/HLSLResource.h
@@ -25,6 +25,7 @@ enum class ResourceClass : uint8_t {
   SRV = 0,
   UAV,
   CBuffer,
+  TBuffer,
   Sampler,
   Invalid,
   NumClasses = Invalid,

>From dcaf3ad9012e5f2fd12219da2e0204470a41c7a9 Mon Sep 17 00:00:00 2001
From: Joshua Batista <jbatista at microsoft.com>
Date: Tue, 23 Apr 2024 16:59:44 -0700
Subject: [PATCH 09/15] address tex

---
 clang/lib/Sema/SemaDeclAttr.cpp                |  4 ++--
 .../SemaHLSL/resource_binding_attr_error.hlsl  |  2 +-
 .../resource_binding_attr_error_mismatch.hlsl  | 18 +++++++++---------
 3 files changed, 12 insertions(+), 12 deletions(-)

diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index 7095825c7d842..172c68c8dd7e4 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -7355,10 +7355,10 @@ static void DiagnoseHLSLResourceRegType(Sema &S, SourceLocation &ArgLoc,
       PrintingPolicy PP = S.getPrintingPolicy();
       std::string typestr = QualType::getAsString(QT.split(), PP);
 
-      if (Slot[0] != 'b' && Slot[0] != 'c' && Slot[0] != 'i')
+      if (Slot[0] != 't')
         S.Diag(ArgLoc,
                diag::err_hlsl_mismatching_register_builtin_type_and_name)
-            << Slot.substr(0, 1) << typestr << "'b, c, or i";
+            << Slot.substr(0, 1) << typestr << "'t'";
       return;
     }
 
diff --git a/clang/test/SemaHLSL/resource_binding_attr_error.hlsl b/clang/test/SemaHLSL/resource_binding_attr_error.hlsl
index c2e09c116654f..5d3b742eae36f 100644
--- a/clang/test/SemaHLSL/resource_binding_attr_error.hlsl
+++ b/clang/test/SemaHLSL/resource_binding_attr_error.hlsl
@@ -44,7 +44,7 @@ void foo2() {
   // expected-warning at +1 {{'register' attribute only applies to cbuffer/tbuffer and external global variables}}
   extern RWBuffer<float> U2 : register(u5);
 }
-// expected-error at +1 {{invalid register name prefix 'u' for 'float' (expected 'b, c, or i)}}
+// expected-error at +1 {{invalid register name prefix 'u' for 'float' (expected 't')}}
 float b : register(u0, space1);
 
 // expected-warning at +1 {{'register' attribute only applies to cbuffer/tbuffer and external global variables}}
diff --git a/clang/test/SemaHLSL/resource_binding_attr_error_mismatch.hlsl b/clang/test/SemaHLSL/resource_binding_attr_error_mismatch.hlsl
index 4bff910c0a7a4..32bf3c510f2ac 100644
--- a/clang/test/SemaHLSL/resource_binding_attr_error_mismatch.hlsl
+++ b/clang/test/SemaHLSL/resource_binding_attr_error_mismatch.hlsl
@@ -20,22 +20,22 @@ RWBuffer<int> b : register(t2, space1);
 // NOT YET IMPLEMENTED : {{invalid register name prefix 't' for register type 'RWTexture3D' (expected 'u')}}
 // NOT YET IMPLEMENTED RWTexture3D<float4> RWT3D_u1 : register(t1)
 
-// NOT YET IMPLEMENTED : {{invalid register name prefix 'b' for register type 'Texture2DMS' (expected 't' or 's')}}
-// NOT YET IMPLEMENTED TextureCube TCube_b2 : register(B2);
+// NOT YET IMPLEMENTED : {{invalid register name prefix 'b' for register type 'TextureCube' (expected 't')}}
+// NOT YET IMPLEMENTED TextureCube <float>  t8 : register(b8);
 
-// NOT YET IMPLEMENTED : {{invalid register name prefix 'b' for register type 'Texture2DMS' (expected 't')}}
+// NOT YET IMPLEMENTED : {{invalid register name prefix 'b' for register type 'TextureCubeArray' (expected 't')}}
 // NOT YET IMPLEMENTED TextureCubeArray TCubeArray_t2 : register(b2);
 
-// NOT YET IMPLEMENTED : {{invalid register name prefix 'b' for register type 'Texture2DMS' (expected 't' or 's')}}
+// NOT YET IMPLEMENTED : {{invalid register name prefix 'b' for register type 'Texture1DArray' (expected 't')}}
 // NOT YET IMPLEMENTED Texture1DArray T1DArray_t2 : register(b2);
 
-// NOT YET IMPLEMENTED : {{invalid register name prefix 'u' for register type 'Texture2DMS' (expected 't' or 's')}}
+// NOT YET IMPLEMENTED : {{invalid register name prefix 'u' for register type 'Texture2DArray' (expected 't')}}
 // NOT YET IMPLEMENTED Texture2DArray T2DArray_b2 : register(B2);
 
-// NOT YET IMPLEMENTED : {{invalid register name prefix 'u' for register type 'Texture2DMS' (expected 'b' or 'c' or 'i')}}
+// NOT YET IMPLEMENTED : {{invalid register name prefix 'u' for register type 'Texture2DMSArray' (expected 't')}}
 // NOT YET IMPLEMENTED Texture2DMSArray<float4> msTextureArray : register(t2, space2);
 
-// NOT YET IMPLEMENTED : {{invalid register name prefix 'u' for register type 'TCubeArray_f2' (expected 't' or 's')}}
+// NOT YET IMPLEMENTED : {{invalid register name prefix 'u' for register type 'TextureCubeArray' (expected 't')}}
 // NOT YET IMPLEMENTED TextureCubeArray TCubeArray_f2 : register(u2);
 
 // NOT YET IMPLEMENTED : {{invalid register name prefix 'u' for register type 'TypedBuffer' (expected 't')}}
@@ -59,10 +59,10 @@ tbuffer f : register(s2, space1) {}
 
 // NOT YET IMPLEMENTED : RTAccelerationStructure doesn't have any example tests in DXC
 
-// NOT YET IMPLEMENTED : {{invalid register name prefix 'u' for register type 'FeedbackTexture2D' (expected 'b' or 'c' or 'i')}}
+// NOT YET IMPLEMENTED : {{invalid register name prefix 'u' for register type 'FeedbackTexture2D' (expected 't')}}
 // NOT YET IMPLEMENTED FeedbackTexture2D<float> FBTex2D[3][] : register(u0, space26);
 
-// NOT YET IMPLEMENTED : {{invalid register name prefix 'u' for register type 'FeedbackTexture2DArray' (expected 'b' or 'c' or 'i')}}
+// NOT YET IMPLEMENTED : {{invalid register name prefix 'u' for register type 'FeedbackTexture2DArray' (expected 't')}}
 // NOT YET IMPLEMENTED FeedbackTexture2DArray<float> FBTex2DArr[3][2][] : register(u0, space27);
 
 

>From 1edee6ed24c1c4f5321e1352556bc2d4c1146c95 Mon Sep 17 00:00:00 2001
From: Joshua Batista <jbatista at microsoft.com>
Date: Wed, 24 Apr 2024 15:44:22 -0700
Subject: [PATCH 10/15] clean up switch statement, remove bad comments

---
 clang/lib/Sema/SemaDeclAttr.cpp               | 32 +++++++------------
 .../resource_binding_attr_error_mismatch.hlsl |  3 +-
 2 files changed, 13 insertions(+), 22 deletions(-)

diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index 172c68c8dd7e4..9682e9c6694ce 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -7387,38 +7387,28 @@ static void DiagnoseHLSLResourceRegType(Sema &S, SourceLocation &ArgLoc,
   }
   switch (DeclResourceClass) {
   case llvm::hlsl::ResourceClass::SRV: {
-    if (Slot[0] != 't')
-      S.Diag(ArgLoc, diag::err_hlsl_mismatching_register_resource_type_and_name)
-          << Slot.substr(0, 1) << VarTy
-          << (unsigned)llvm::hlsl::ResourceClass::SRV;
+    if (Slot[0] == 't')
+      return;
     break;
   }
   case llvm::hlsl::ResourceClass::UAV: {
-    if (Slot[0] != 'u')
-      S.Diag(ArgLoc, diag::err_hlsl_mismatching_register_resource_type_and_name)
-          << Slot.substr(0, 1) << VarTy
-          << (unsigned)llvm::hlsl::ResourceClass::UAV;
+    if (Slot[0] == 'u')
+      return;
     break;
   }
   case llvm::hlsl::ResourceClass::CBuffer: {
-    if (Slot[0] != 'b')
-      S.Diag(ArgLoc, diag::err_hlsl_mismatching_register_resource_type_and_name)
-          << Slot.substr(0, 1) << VarTy
-          << (unsigned)llvm::hlsl::ResourceClass::CBuffer;
+    if (Slot[0] == 'b')
+      return;
     break;
   }
   case llvm::hlsl::ResourceClass::TBuffer: {
-    if (Slot[0] != 't')
-      S.Diag(ArgLoc, diag::err_hlsl_mismatching_register_resource_type_and_name)
-          << Slot.substr(0, 1) << VarTy
-          << (unsigned)llvm::hlsl::ResourceClass::TBuffer;
+    if (Slot[0] == 't')
+      return;
     break;
   }
   case llvm::hlsl::ResourceClass::Sampler: {
-    if (Slot[0] != 's')
-      S.Diag(ArgLoc, diag::err_hlsl_mismatching_register_resource_type_and_name)
-          << Slot.substr(0, 1) << VarTy
-          << (unsigned)llvm::hlsl::ResourceClass::Sampler;
+    if (Slot[0] == 's')
+      return;
     break;
   }
   case llvm::hlsl::ResourceClass::Invalid: {
@@ -7426,6 +7416,8 @@ static void DiagnoseHLSLResourceRegType(Sema &S, SourceLocation &ArgLoc,
     break;
   }
   }
+  S.Diag(ArgLoc, diag::err_hlsl_mismatching_register_resource_type_and_name)
+      << Slot.substr(0, 1) << VarTy << (unsigned)DeclResourceClass;
 }
 
 static void handleHLSLResourceBindingAttr(Sema &S, Decl *D,
diff --git a/clang/test/SemaHLSL/resource_binding_attr_error_mismatch.hlsl b/clang/test/SemaHLSL/resource_binding_attr_error_mismatch.hlsl
index 32bf3c510f2ac..249a24d980ba5 100644
--- a/clang/test/SemaHLSL/resource_binding_attr_error_mismatch.hlsl
+++ b/clang/test/SemaHLSL/resource_binding_attr_error_mismatch.hlsl
@@ -1,10 +1,9 @@
 // RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -x hlsl -o - -fsyntax-only %s -verify
 
-// the below will cause an llvm unreachable, because RWBuffers don't have resource attributes yet
+
 // expected-error at +1  {{invalid register name prefix 'b' for register resource type 'RWBuffer' (expected 'u')}}
 RWBuffer<int> a : register(b2, space1);
 
-// the below will cause an llvm unreachable, because RWBuffers don't have resource attributes yet
 // expected-error at +1  {{invalid register name prefix 't' for register resource type 'RWBuffer' (expected 'u')}}
 RWBuffer<int> b : register(t2, space1);
 

>From 9bdcea237858ca581681bf7b75d54af24376ce09 Mon Sep 17 00:00:00 2001
From: Joshua Batista <jbatista at microsoft.com>
Date: Thu, 25 Apr 2024 09:56:25 -0700
Subject: [PATCH 11/15] remove tbuffer as a resource class

---
 clang/lib/Sema/SemaDeclAttr.cpp               | 28 +++++++++----------
 .../include/llvm/Frontend/HLSL/HLSLResource.h |  1 -
 2 files changed, 14 insertions(+), 15 deletions(-)

diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index 9682e9c6694ce..095290caf14c0 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -7377,13 +7377,7 @@ static void DiagnoseHLSLResourceRegType(Sema &S, SourceLocation &ArgLoc,
     DeclResourceClass = Attr->getResourceClass();
     VarTy = TheRecordDecl->getName();
   } else {
-    if (CBufferOrTBuffer->isCBuffer()) {
-      DeclResourceClass = llvm::hlsl::ResourceClass::CBuffer;
-      VarTy = "cbuffer";
-    } else {
-      DeclResourceClass = llvm::hlsl::ResourceClass::TBuffer;
-      VarTy = "tbuffer";
-    }
+    DeclResourceClass = llvm::hlsl::ResourceClass::CBuffer;
   }
   switch (DeclResourceClass) {
   case llvm::hlsl::ResourceClass::SRV: {
@@ -7397,13 +7391,19 @@ static void DiagnoseHLSLResourceRegType(Sema &S, SourceLocation &ArgLoc,
     break;
   }
   case llvm::hlsl::ResourceClass::CBuffer: {
-    if (Slot[0] == 'b')
-      return;
-    break;
-  }
-  case llvm::hlsl::ResourceClass::TBuffer: {
-    if (Slot[0] == 't')
-      return;
+    // could be CBuffer or TBuffer
+    if (CBufferOrTBuffer->isCBuffer()) {
+      VarTy = "cbuffer";
+      if (Slot[0] == 'b')
+        return;
+    } else {
+      VarTy = "tbuffer";
+      // This isn't an SRV, but we need the diagnostic to emit
+      // the same binding prefix that would be expected on an SRV.
+      DeclResourceClass = llvm::hlsl::ResourceClass::SRV;
+      if (Slot[0] == 't')
+        return;
+    }
     break;
   }
   case llvm::hlsl::ResourceClass::Sampler: {
diff --git a/llvm/include/llvm/Frontend/HLSL/HLSLResource.h b/llvm/include/llvm/Frontend/HLSL/HLSLResource.h
index 61ec920b76092..edfcbda0a3bb3 100644
--- a/llvm/include/llvm/Frontend/HLSL/HLSLResource.h
+++ b/llvm/include/llvm/Frontend/HLSL/HLSLResource.h
@@ -25,7 +25,6 @@ enum class ResourceClass : uint8_t {
   SRV = 0,
   UAV,
   CBuffer,
-  TBuffer,
   Sampler,
   Invalid,
   NumClasses = Invalid,

>From 8baae27d31369c8ca060062a433844a7fe85a1cd Mon Sep 17 00:00:00 2001
From: Joshua Batista <jbatista at microsoft.com>
Date: Wed, 1 May 2024 13:50:50 -0700
Subject: [PATCH 12/15] add resource attr to hlslbufferdecl, drive diags from
 attr. Also disallow builtin types as resource types

---
 .../clang/Basic/DiagnosticSemaKinds.td        |  5 ++--
 clang/include/clang/Sema/SemaHLSL.h           |  2 +-
 clang/lib/Sema/SemaDeclAttr.cpp               | 25 +++++++++----------
 clang/lib/Sema/SemaHLSL.cpp                   | 23 ++++++++++++++++-
 .../ast-dump-comment-cbuffe-tbufferr.hlsl     |  2 ++
 clang/test/AST/HLSL/cbuffer_tbuffer.hlsl      |  6 +++--
 clang/test/AST/HLSL/pch_hlsl_buffer.hlsl      |  2 ++
 .../test/AST/HLSL/resource_binding_attr.hlsl  |  6 +++--
 .../SemaHLSL/resource_binding_attr_error.hlsl |  2 +-
 9 files changed, 51 insertions(+), 22 deletions(-)

diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index de940625b44b4..ff013b68036a0 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -12154,9 +12154,10 @@ def err_hlsl_missing_semantic_annotation : Error<
 def err_hlsl_init_priority_unsupported : Error<
   "initializer priorities are not supported in HLSL">;
 
-def err_hlsl_mismatching_register_resource_type_and_name: Error<"invalid register name prefix '%0' for register resource type '%1' (expected %select{'t'|'u'|'b'|'t'|'s'}2)">;
+def err_hlsl_mismatching_register_resource_type_and_name: Error<"invalid register name prefix '%0' for register resource type '%1' (expected %select{'t'|'u'|'b'|'s'}2)">;
 def err_hlsl_mismatching_register_builtin_type_and_name: Error<"invalid register name prefix '%0' for '%1' (expected %2)">;
-def err_hlsl_unsupported_register_type : Error<"invalid resource class specifier '%0' used; expected 'b', 's', 't', or 'u'">;
+def err_hlsl_unsupported_register_prefix : Error<"invalid resource class specifier '%0' used; expected 'b', 's', 't', or 'u'">;
+def err_hlsl_unsupported_register_resource_type : Error<"invalid resource '%0' used">;
 def err_hlsl_unsupported_register_number : Error<"register number should be an integer">;
 def err_hlsl_expected_space : Error<"invalid space specifier '%0' used; expected 'space' followed by an integer, like space1">;
 def err_hlsl_pointers_unsupported : Error<
diff --git a/clang/include/clang/Sema/SemaHLSL.h b/clang/include/clang/Sema/SemaHLSL.h
index 34acaf19517f2..3dce9eed79fbd 100644
--- a/clang/include/clang/Sema/SemaHLSL.h
+++ b/clang/include/clang/Sema/SemaHLSL.h
@@ -29,7 +29,7 @@ namespace clang {
 class SemaHLSL : public SemaBase {
 public:
   SemaHLSL(Sema &S);
-
+  HLSLResourceAttr *mergeHLSLResourceAttr(bool CBuffer);
   Decl *ActOnStartBuffer(Scope *BufferScope, bool CBuffer, SourceLocation KwLoc,
                          IdentifierInfo *Ident, SourceLocation IdentLoc,
                          SourceLocation LBrace);
diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index 095290caf14c0..3b03cdeaad900 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -7355,10 +7355,8 @@ static void DiagnoseHLSLResourceRegType(Sema &S, SourceLocation &ArgLoc,
       PrintingPolicy PP = S.getPrintingPolicy();
       std::string typestr = QualType::getAsString(QT.split(), PP);
 
-      if (Slot[0] != 't')
-        S.Diag(ArgLoc,
-               diag::err_hlsl_mismatching_register_builtin_type_and_name)
-            << Slot.substr(0, 1) << typestr << "'t'";
+      S.Diag(ArgLoc, diag::err_hlsl_unsupported_register_resource_type)
+          << typestr;
       return;
     }
 
@@ -7377,7 +7375,13 @@ static void DiagnoseHLSLResourceRegType(Sema &S, SourceLocation &ArgLoc,
     DeclResourceClass = Attr->getResourceClass();
     VarTy = TheRecordDecl->getName();
   } else {
-    DeclResourceClass = llvm::hlsl::ResourceClass::CBuffer;
+    HLSLResourceAttr *Attr = CBufferOrTBuffer->getAttr<HLSLResourceAttr>();
+    DeclResourceClass = Attr->getResourceClass();
+    if (CBufferOrTBuffer->isCBuffer()) {
+      VarTy = "cbuffer";
+    } else {
+      VarTy = "tbuffer";
+    }
   }
   switch (DeclResourceClass) {
   case llvm::hlsl::ResourceClass::SRV: {
@@ -7392,15 +7396,10 @@ static void DiagnoseHLSLResourceRegType(Sema &S, SourceLocation &ArgLoc,
   }
   case llvm::hlsl::ResourceClass::CBuffer: {
     // could be CBuffer or TBuffer
-    if (CBufferOrTBuffer->isCBuffer()) {
-      VarTy = "cbuffer";
+    if (VarTy == "cbuffer") {
       if (Slot[0] == 'b')
         return;
-    } else {
-      VarTy = "tbuffer";
-      // This isn't an SRV, but we need the diagnostic to emit
-      // the same binding prefix that would be expected on an SRV.
-      DeclResourceClass = llvm::hlsl::ResourceClass::SRV;
+    } else if (VarTy == "tbuffer") {
       if (Slot[0] == 't')
         return;
     }
@@ -7460,7 +7459,7 @@ static void handleHLSLResourceBindingAttr(Sema &S, Decl *D,
     case 't':
       break;
     default:
-      S.Diag(ArgLoc, diag::err_hlsl_unsupported_register_type)
+      S.Diag(ArgLoc, diag::err_hlsl_unsupported_register_prefix)
           << Slot.substr(0, 1);
       return;
     }
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index bb9e37f18d370..a6be865c78dd0 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -24,6 +24,25 @@ using namespace clang;
 
 SemaHLSL::SemaHLSL(Sema &S) : SemaBase(S) {}
 
+HLSLResourceAttr *SemaHLSL::mergeHLSLResourceAttr(bool CBuffer) {
+  // cbuffer case
+  if (CBuffer) {
+    HLSLResourceAttr *attr = HLSLResourceAttr::CreateImplicit(
+        getASTContext(), llvm::hlsl::ResourceClass::CBuffer,
+        llvm::hlsl::ResourceKind::CBuffer,
+        /*IsROV=*/false);
+    return attr;
+  }
+  // tbuffer case
+  else {
+    HLSLResourceAttr *attr = HLSLResourceAttr::CreateImplicit(
+        getASTContext(), llvm::hlsl::ResourceClass::SRV,
+        llvm::hlsl::ResourceKind::TBuffer,
+        /*IsROV=*/false);
+    return attr;
+  }
+}
+
 Decl *SemaHLSL::ActOnStartBuffer(Scope *BufferScope, bool CBuffer,
                                  SourceLocation KwLoc, IdentifierInfo *Ident,
                                  SourceLocation IdentLoc,
@@ -32,7 +51,9 @@ Decl *SemaHLSL::ActOnStartBuffer(Scope *BufferScope, bool CBuffer,
   DeclContext *LexicalParent = SemaRef.getCurLexicalContext();
   HLSLBufferDecl *Result = HLSLBufferDecl::Create(
       getASTContext(), LexicalParent, CBuffer, KwLoc, Ident, IdentLoc, LBrace);
-
+  HLSLResourceAttr *NewAttr = mergeHLSLResourceAttr(CBuffer);
+  if (NewAttr)
+    Result->addAttr(NewAttr);
   SemaRef.PushOnScopeChains(Result, BufferScope);
   SemaRef.PushDeclContext(BufferScope, Result);
 
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 a98dc0f4ce431..121b490b5c731 100644
--- a/clang/test/AST/HLSL/ast-dump-comment-cbuffe-tbufferr.hlsl
+++ b/clang/test/AST/HLSL/ast-dump-comment-cbuffe-tbufferr.hlsl
@@ -38,12 +38,14 @@ tbuffer B {
 }
 
 // AST:HLSLBufferDecl {{.*}}:11:1, line:20:1> line:11:9 cbuffer A
+// AST-NEXT:HLSLResourceAttr {{.*}} <<invalid sloc>> Implicit CBuffer 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:HLSLBufferDecl {{.*}}<line:29:1, line:38:1> line:29:9 tbuffer B
+// AST-NEXT:HLSLResourceAttr {{.*}} <<invalid sloc>> Implicit SRV 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."
diff --git a/clang/test/AST/HLSL/cbuffer_tbuffer.hlsl b/clang/test/AST/HLSL/cbuffer_tbuffer.hlsl
index 7204dcd16e0a9..a67688d510ea6 100644
--- a/clang/test/AST/HLSL/cbuffer_tbuffer.hlsl
+++ b/clang/test/AST/HLSL/cbuffer_tbuffer.hlsl
@@ -1,12 +1,14 @@
 // 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:5:9 cbuffer CB
+// CHECK:HLSLBufferDecl 0x[[CB:[0-9a-f]+]] {{.*}} line:6:9 cbuffer CB
+// CHECK-NEXT:HLSLResourceAttr {{.*}} <<invalid sloc>> Implicit CBuffer 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:11:9 tbuffer TB
+// CHECK:HLSLBufferDecl 0x[[TB:[0-9a-f]+]] {{.*}} line:13:9 tbuffer TB
+// CHECK-NEXT:HLSLResourceAttr {{.*}} <<invalid sloc>> Implicit SRV TBuffer
 // CHECK-NEXT:VarDecl 0x[[B:[0-9a-f]+]] {{.*}} col:9 used b 'float'
 tbuffer TB {
   float b;
diff --git a/clang/test/AST/HLSL/pch_hlsl_buffer.hlsl b/clang/test/AST/HLSL/pch_hlsl_buffer.hlsl
index 0277d4756db88..c3552a7c4a142 100644
--- a/clang/test/AST/HLSL/pch_hlsl_buffer.hlsl
+++ b/clang/test/AST/HLSL/pch_hlsl_buffer.hlsl
@@ -17,8 +17,10 @@ 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:HLSLResourceAttr {{.*}} <<invalid sloc>> Implicit CBuffer 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:HLSLResourceAttr {{.*}} <<invalid sloc>> Implicit SRV TBuffer
 // CHECK-NEXT:`-VarDecl 0x[[B:[0-9a-f]+]] <line:12:3, col:9> col:9 imported used 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>
diff --git a/clang/test/AST/HLSL/resource_binding_attr.hlsl b/clang/test/AST/HLSL/resource_binding_attr.hlsl
index 71900f2dbda55..9752494f5adc9 100644
--- a/clang/test/AST/HLSL/resource_binding_attr.hlsl
+++ b/clang/test/AST/HLSL/resource_binding_attr.hlsl
@@ -1,13 +1,15 @@
 // 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:6:9 cbuffer CB
+// CHECK:HLSLBufferDecl 0x[[CB:[0-9a-f]+]] {{.*}} line:7:9 cbuffer CB
+// CHECK-NEXT:HLSLResourceAttr 0x[[CB:[0-9a-f]+]] {{.*}} Implicit CBuffer CBuffer
 // CHECK-NEXT:HLSLResourceBindingAttr 0x{{[0-9a-f]+}} <col:14> "b3" "space2"
 // CHECK-NEXT:VarDecl 0x[[A:[0-9a-f]+]] {{.*}} col:9 used a 'float'
 cbuffer CB : register(b3, space2) {
   float a;
 }
 
-// CHECK:HLSLBufferDecl 0x[[TB:[0-9a-f]+]] {{.*}} line:13:9 tbuffer TB
+// CHECK:HLSLBufferDecl 0x[[TB:[0-9a-f]+]] {{.*}} line:15:9 tbuffer TB
+// CHECK-NEXT:HLSLResourceAttr 0x[[CB:[0-9a-f]+]] {{.*}} Implicit SRV TBuffer
 // CHECK-NEXT:HLSLResourceBindingAttr 0x{{[0-9a-f]+}} <col:14> "t2" "space1"
 // CHECK-NEXT:VarDecl 0x[[B:[0-9a-f]+]] {{.*}} col:9 used b 'float'
 tbuffer TB : register(t2, space1) {
diff --git a/clang/test/SemaHLSL/resource_binding_attr_error.hlsl b/clang/test/SemaHLSL/resource_binding_attr_error.hlsl
index 5d3b742eae36f..a274905f087ef 100644
--- a/clang/test/SemaHLSL/resource_binding_attr_error.hlsl
+++ b/clang/test/SemaHLSL/resource_binding_attr_error.hlsl
@@ -44,7 +44,7 @@ void foo2() {
   // expected-warning at +1 {{'register' attribute only applies to cbuffer/tbuffer and external global variables}}
   extern RWBuffer<float> U2 : register(u5);
 }
-// expected-error at +1 {{invalid register name prefix 'u' for 'float' (expected 't')}}
+// expected-error at +1 {{invalid resource 'float' used}}
 float b : register(u0, space1);
 
 // expected-warning at +1 {{'register' attribute only applies to cbuffer/tbuffer and external global variables}}

>From 80d7209d27ffde905b6c5f1fdddc0dc83fb64fb6 Mon Sep 17 00:00:00 2001
From: Joshua Batista <jbatista at microsoft.com>
Date: Thu, 2 May 2024 13:00:33 -0700
Subject: [PATCH 13/15] Update
 clang/test/SemaHLSL/resource_binding_attr_error_mismatch.hlsl

Co-authored-by: Damyan Pepper <damyanp at microsoft.com>
---
 clang/test/SemaHLSL/resource_binding_attr_error_mismatch.hlsl | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/clang/test/SemaHLSL/resource_binding_attr_error_mismatch.hlsl b/clang/test/SemaHLSL/resource_binding_attr_error_mismatch.hlsl
index 249a24d980ba5..57f540d70c7c8 100644
--- a/clang/test/SemaHLSL/resource_binding_attr_error_mismatch.hlsl
+++ b/clang/test/SemaHLSL/resource_binding_attr_error_mismatch.hlsl
@@ -28,9 +28,10 @@ RWBuffer<int> b : register(t2, space1);
 // NOT YET IMPLEMENTED : {{invalid register name prefix 'b' for register type 'Texture1DArray' (expected 't')}}
 // NOT YET IMPLEMENTED Texture1DArray T1DArray_t2 : register(b2);
 
-// NOT YET IMPLEMENTED : {{invalid register name prefix 'u' for register type 'Texture2DArray' (expected 't')}}
+// NOT YET IMPLEMENTED : {{invalid register name prefix 'B' for register type 'Texture2DArray' (expected 't')}}
 // NOT YET IMPLEMENTED Texture2DArray T2DArray_b2 : register(B2);
 
+
 // NOT YET IMPLEMENTED : {{invalid register name prefix 'u' for register type 'Texture2DMSArray' (expected 't')}}
 // NOT YET IMPLEMENTED Texture2DMSArray<float4> msTextureArray : register(t2, space2);
 

>From 6888ea8ddcd584b479afe7d661fd01b1fd8afb5c Mon Sep 17 00:00:00 2001
From: Joshua Batista <jbatista at microsoft.com>
Date: Wed, 12 Jun 2024 17:37:39 -0700
Subject: [PATCH 14/15] write code for flag set step, except for recursive udt
 step

---
 clang/lib/Sema/SemaDeclAttr.cpp | 208 ++++++++++++++++++++------------
 1 file changed, 134 insertions(+), 74 deletions(-)

diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index 3b03cdeaad900..2f88e0537d337 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -7334,89 +7334,147 @@ static void handleHLSLShaderAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
     D->addAttr(NewAttr);
 }
 
-static void DiagnoseHLSLResourceRegType(Sema &S, SourceLocation &ArgLoc,
-                                        Decl *D, StringRef &Slot) {
-  // Samplers, UAVs, and SRVs are VarDecl types
-  VarDecl *SamplerUAVOrSRV = dyn_cast<VarDecl>(D);
-  // Cbuffers and Tbuffers are HLSLBufferDecl types
-  HLSLBufferDecl *CBufferOrTBuffer = dyn_cast<HLSLBufferDecl>(D);
-  if (!SamplerUAVOrSRV && !CBufferOrTBuffer)
-    return;
-
-  llvm::hlsl::ResourceClass DeclResourceClass;
-  StringRef VarTy = "";
-  if (SamplerUAVOrSRV) {
-    const Type *Ty = SamplerUAVOrSRV->getType()->getPointeeOrArrayElementType();
-    if (!Ty)
-      llvm_unreachable("Resource class must have an element type.");
+struct register_binding_flags {
+  bool resource = false;
+  bool udt = false;
+  bool other = false;
+  bool basic = false;
+
+  bool srv;
+  bool uav;
+  bool cbv;
+  bool sampler;
+
+  bool contains_numeric = false;
+  bool default_globals = false;
+  bool is_member = false;
+};
 
-    if (const BuiltinType *BTy = dyn_cast<BuiltinType>(Ty)) {
-      QualType QT = SamplerUAVOrSRV->getType();
-      PrintingPolicy PP = S.getPrintingPolicy();
-      std::string typestr = QualType::getAsString(QT.split(), PP);
+bool isDeclaredWithinCOrTBuffer(const Decl *decl) {
+  if (!decl)
+    return false;
 
-      S.Diag(ArgLoc, diag::err_hlsl_unsupported_register_resource_type)
-          << typestr;
-      return;
+  // Traverse up the parent contexts
+  const DeclContext *context = decl->getDeclContext();
+  while (context) {
+    if (isa<HLSLBufferDecl>(context)) {
+      return true;
     }
+    context = context->getParent();
+  }
 
-    const CXXRecordDecl *TheRecordDecl = Ty->getAsCXXRecordDecl();
-    if (!TheRecordDecl)
-      llvm_unreachable(
-          "Resource class should have a resource type declaration.");
+  return false;
+}
 
-    if (auto TDecl = dyn_cast<ClassTemplateSpecializationDecl>(TheRecordDecl))
-      TheRecordDecl = TDecl->getSpecializedTemplate()->getTemplatedDecl();
-    TheRecordDecl = TheRecordDecl->getCanonicalDecl();
-    const auto *Attr = TheRecordDecl->getAttr<HLSLResourceAttr>();
-    if (!Attr)
-      llvm_unreachable("Resource class should have a resource attribute.");
 
-    DeclResourceClass = Attr->getResourceClass();
-    VarTy = TheRecordDecl->getName();
-  } else {
-    HLSLResourceAttr *Attr = CBufferOrTBuffer->getAttr<HLSLResourceAttr>();
-    DeclResourceClass = Attr->getResourceClass();
-    if (CBufferOrTBuffer->isCBuffer()) {
-      VarTy = "cbuffer";
-    } else {
-      VarTy = "tbuffer";
-    }
-  }
-  switch (DeclResourceClass) {
-  case llvm::hlsl::ResourceClass::SRV: {
-    if (Slot[0] == 't')
-      return;
-    break;
-  }
-  case llvm::hlsl::ResourceClass::UAV: {
-    if (Slot[0] == 'u')
-      return;
-    break;
+const HLSLResourceAttr *getHLSLResourceAttrFromVarDecl(VarDecl *SamplerUAVOrSRV) {
+  const Type *Ty = SamplerUAVOrSRV->getType()->getPointeeOrArrayElementType();
+  if (!Ty)
+    llvm_unreachable("Resource class must have an element type.");
+
+  if (const BuiltinType *BTy = dyn_cast<BuiltinType>(Ty)) {
+    /* QualType QT = SamplerUAVOrSRV->getType();
+    PrintingPolicy PP = S.getPrintingPolicy();
+    std::string typestr = QualType::getAsString(QT.split(), PP);
+
+    S.Diag(ArgLoc, diag::err_hlsl_unsupported_register_resource_type)
+        << typestr;
+    return; */
+    return nullptr;
   }
-  case llvm::hlsl::ResourceClass::CBuffer: {
-    // could be CBuffer or TBuffer
-    if (VarTy == "cbuffer") {
-      if (Slot[0] == 'b')
-        return;
-    } else if (VarTy == "tbuffer") {
-      if (Slot[0] == 't')
-        return;
+
+  const CXXRecordDecl *TheRecordDecl = Ty->getAsCXXRecordDecl();
+  if (!TheRecordDecl)
+    llvm_unreachable("Resource class should have a resource type declaration.");
+
+  if (auto TDecl = dyn_cast<ClassTemplateSpecializationDecl>(TheRecordDecl))
+    TheRecordDecl = TDecl->getSpecializedTemplate()->getTemplatedDecl();
+  TheRecordDecl = TheRecordDecl->getCanonicalDecl();
+  const auto *Attr = TheRecordDecl->getAttr<HLSLResourceAttr>();
+  return Attr;
+}
+
+register_binding_flags HLSLFillRegisterBindingFlags(Sema &S, Decl *D) {
+  register_binding_flags r;
+  if (!isDeclaredWithinCOrTBuffer(D)) {
+    // make sure the type is a basic / numeric type
+    if (VarDecl *v = dyn_cast<VarDecl>(D)) {
+      QualType t = v->getType();
+      // a numeric variable will inevitably end up in $Globals buffer
+      if (t->isIntegralType(S.getASTContext()) || t->isFloatingType())         
+        r.default_globals = true;      
     }
-    break;
-  }
-  case llvm::hlsl::ResourceClass::Sampler: {
-    if (Slot[0] == 's')
-      return;
-    break;
   }
-  case llvm::hlsl::ResourceClass::Invalid: {
-    llvm_unreachable("Resource class should be valid.");
-    break;
+  // Cbuffers and Tbuffers are HLSLBufferDecl types
+  HLSLBufferDecl *CBufferOrTBuffer = dyn_cast<HLSLBufferDecl>(D);
+  // Samplers, UAVs, and SRVs are VarDecl types
+  VarDecl *SamplerUAVOrSRV = dyn_cast<VarDecl>(D);
+
+  if (CBufferOrTBuffer) {
+    r.resource = true;
+    if (CBufferOrTBuffer->isCBuffer())
+      r.cbv = true;   
+    else 
+      r.srv = true;
+  } 
+  else if (SamplerUAVOrSRV) {
+    const HLSLResourceAttr *res_attr =
+        getHLSLResourceAttrFromVarDecl(SamplerUAVOrSRV);
+    if (res_attr) {
+      llvm::hlsl::ResourceClass DeclResourceClass =
+          res_attr->getResourceClass();
+      r.resource = true;
+      switch (DeclResourceClass) {
+      case llvm::hlsl::ResourceClass::SRV: {
+        r.srv = true;
+        break;
+      }
+      case llvm::hlsl::ResourceClass::UAV: {
+        r.uav = true;
+        break;
+      }
+      case llvm::hlsl::ResourceClass::CBuffer: {
+        r.cbv = true;
+        break;
+      }
+      case llvm::hlsl::ResourceClass::Sampler: {
+        r.sampler = true;
+        break;
+      }
+      case llvm::hlsl::ResourceClass::Invalid: {          
+        llvm_unreachable("Resource class should be valid.");
+        break;
+      }
+      }
+    }
+    else {
+      if (SamplerUAVOrSRV->getType()->isBuiltinType())
+        r.basic = true;
+      else if (SamplerUAVOrSRV->getType()->isAggregateType()) {        
+        r.udt = true;
+        // recurse through members, set appropriate resource class flags.
+      }
+      else
+        r.other = true;
+    }
   }
+  else {
+    llvm_unreachable("unknown decl type");
   }
-  S.Diag(ArgLoc, diag::err_hlsl_mismatching_register_resource_type_and_name)
-      << Slot.substr(0, 1) << VarTy << (unsigned)DeclResourceClass;
+  return r;
+}
+
+
+static void DiagnoseHLSLResourceRegType(Sema &S, SourceLocation &ArgLoc,
+                                        Decl *D, StringRef &Slot) {
+
+  register_binding_flags f = HLSLFillRegisterBindingFlags(S, D);
+  // Samplers, UAVs, and SRVs are VarDecl types
+  VarDecl *SamplerUAVOrSRV = dyn_cast<VarDecl>(D);
+  // Cbuffers and Tbuffers are HLSLBufferDecl types
+  HLSLBufferDecl *CBufferOrTBuffer = dyn_cast<HLSLBufferDecl>(D);
+  if (!SamplerUAVOrSRV && !CBufferOrTBuffer)
+    return; 
 }
 
 static void handleHLSLResourceBindingAttr(Sema &S, Decl *D,
@@ -7453,10 +7511,12 @@ static void handleHLSLResourceBindingAttr(Sema &S, Decl *D,
   // Validate.
   if (!Slot.empty()) {
     switch (Slot[0]) {
+    case 't':
     case 'u':
     case 'b':
-    case 's':
-    case 't':
+    case 's':    
+    case 'c':
+    case 'i':
       break;
     default:
       S.Diag(ArgLoc, diag::err_hlsl_unsupported_register_prefix)

>From 6bc286e484e6062f252239ef0d52d6b93d245cd1 Mon Sep 17 00:00:00 2001
From: Joshua Batista <jbatista at microsoft.com>
Date: Thu, 20 Jun 2024 16:16:09 -0700
Subject: [PATCH 15/15] add recursive flag setting code, and parse hlsl
 semantics inside struct members, remove is_member

---
 clang/include/clang/Basic/Attr.td |  2 +-
 clang/lib/Parse/ParseDecl.cpp     |  2 +
 clang/lib/Parse/ParseDeclCXX.cpp  |  3 ++
 clang/lib/Sema/SemaDeclAttr.cpp   | 76 ++++++++++++++++++++++++++++---
 4 files changed, 76 insertions(+), 7 deletions(-)

diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td
index dc87a8c6f022d..e7f2b0640c20b 100644
--- a/clang/include/clang/Basic/Attr.td
+++ b/clang/include/clang/Basic/Attr.td
@@ -4366,7 +4366,7 @@ def HLSLSV_GroupIndex: HLSLAnnotationAttr {
 
 def HLSLResourceBinding: InheritableAttr {
   let Spellings = [HLSLSemantic<"register">];
-  let Subjects = SubjectList<[HLSLBufferObj, ExternalGlobalVar]>;
+  let Subjects = SubjectList<[HLSLBufferObj, ExternalGlobalVar], ErrorDiag>;
   let LangOpts = [HLSL];
   let Args = [StringArgument<"Slot">, StringArgument<"Space", 1>];
   let Documentation = [HLSLResourceBindingDocs];
diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index 5f26b5a9e46be..3c18568a0bbba 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -4859,6 +4859,8 @@ void Parser::ParseStructDeclaration(
 
     // If attributes exist after the declarator, parse them.
     MaybeParseGNUAttributes(DeclaratorInfo.D);
+    if (getLangOpts().HLSL)
+      MaybeParseHLSLSemantics(DeclaratorInfo.D);
 
     // We're done with this declarator;  invoke the callback.
     FieldsCallback(DeclaratorInfo);
diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp
index 8e0e868248293..3050509163fee 100644
--- a/clang/lib/Parse/ParseDeclCXX.cpp
+++ b/clang/lib/Parse/ParseDeclCXX.cpp
@@ -2649,6 +2649,9 @@ bool Parser::ParseCXXMemberDeclaratorBeforeInitializer(
   else
     DeclaratorInfo.SetIdentifier(nullptr, Tok.getLocation());
 
+  if (getLangOpts().HLSL)
+    MaybeParseHLSLSemantics(DeclaratorInfo);
+
   if (!DeclaratorInfo.isFunctionDeclarator() && TryConsumeToken(tok::colon)) {
     assert(DeclaratorInfo.isPastIdentifier() &&
            "don't know where identifier would go yet?");
diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index 2f88e0537d337..3f01931775458 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -7340,14 +7340,13 @@ struct register_binding_flags {
   bool other = false;
   bool basic = false;
 
-  bool srv;
-  bool uav;
-  bool cbv;
-  bool sampler;
+  bool srv = false;
+  bool uav = false;
+  bool cbv = false;
+  bool sampler = false;
 
   bool contains_numeric = false;
   bool default_globals = false;
-  bool is_member = false;
 };
 
 bool isDeclaredWithinCOrTBuffer(const Decl *decl) {
@@ -7394,6 +7393,63 @@ const HLSLResourceAttr *getHLSLResourceAttrFromVarDecl(VarDecl *SamplerUAVOrSRV)
   return Attr;
 }
 
+void traverseType(QualType T, register_binding_flags &r) {
+  if (T->isIntegralOrEnumerationType() || T->isFloatingType()) {
+    r.contains_numeric = true;
+    return;
+  } else if (const RecordType *RT = T->getAs<RecordType>()) {
+    RecordDecl *SubRD = RT->getDecl();
+    if (auto TDecl = dyn_cast<ClassTemplateSpecializationDecl>(SubRD)) {
+      auto TheRecordDecl = TDecl->getSpecializedTemplate()->getTemplatedDecl();
+      TheRecordDecl = TheRecordDecl->getCanonicalDecl();
+      const auto *Attr = TheRecordDecl->getAttr<HLSLResourceAttr>();
+      llvm::hlsl::ResourceClass DeclResourceClass = Attr->getResourceClass();
+      switch (DeclResourceClass) {
+      case llvm::hlsl::ResourceClass::SRV: {
+        r.srv = true;
+        break;
+      }
+      case llvm::hlsl::ResourceClass::UAV: {
+        r.uav = true;
+        break;
+      }
+      case llvm::hlsl::ResourceClass::CBuffer: {
+        r.cbv = true;
+        break;
+      }
+      case llvm::hlsl::ResourceClass::Sampler: {
+        r.sampler = true;
+        break;
+      }
+      case llvm::hlsl::ResourceClass::Invalid: {
+        llvm_unreachable("Resource class should be valid.");
+        break;
+      }
+      }
+    }
+
+    else if (SubRD->isCompleteDefinition()) {
+      for (auto Field : SubRD->fields()) {
+        QualType T = Field->getType();
+        traverseType(T, r);
+      }
+    }
+  }
+}
+
+void setResourceClassFlagsFromRecordDecl(register_binding_flags &r,
+                                         const RecordDecl *RD) {
+  if (!RD)
+    return;
+
+  if (RD->isCompleteDefinition()) {
+    for (auto Field : RD->fields()) {
+      QualType T = Field->getType();
+      traverseType(T, r);
+    }
+  }
+}
+
 register_binding_flags HLSLFillRegisterBindingFlags(Sema &S, Decl *D) {
   register_binding_flags r;
   if (!isDeclaredWithinCOrTBuffer(D)) {
@@ -7452,7 +7508,12 @@ register_binding_flags HLSLFillRegisterBindingFlags(Sema &S, Decl *D) {
         r.basic = true;
       else if (SamplerUAVOrSRV->getType()->isAggregateType()) {        
         r.udt = true;
-        // recurse through members, set appropriate resource class flags.
+        QualType VarType = SamplerUAVOrSRV->getType();
+        if (const RecordType *RT = VarType->getAs<RecordType>()) {
+          const RecordDecl *RD = RT->getDecl();
+          // recurse through members, set appropriate resource class flags.
+          setResourceClassFlagsFromRecordDecl(r, RD);
+        }
       }
       else
         r.other = true;
@@ -7479,6 +7540,9 @@ static void DiagnoseHLSLResourceRegType(Sema &S, SourceLocation &ArgLoc,
 
 static void handleHLSLResourceBindingAttr(Sema &S, Decl *D,
                                           const ParsedAttr &AL) {
+  if (S.RequireCompleteType(D->getBeginLoc(), cast<ValueDecl>(D)->getType(),
+                            diag::err_incomplete_type))
+    return;
   StringRef Space = "space0";
   StringRef Slot = "";
 



More information about the cfe-commits mailing list