[clang] Implement resource binding type prefix mismatch flag setting logic (PR #97103)

Joshua Batista via cfe-commits cfe-commits at lists.llvm.org
Tue Jul 2 16:42:00 PDT 2024


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

>From c784272b3f66ca06be4ab8e72a0963e5ebb6a869 Mon Sep 17 00:00:00 2001
From: Joshua Batista <jbatista at microsoft.com>
Date: Fri, 28 Jun 2024 12:40:56 -0700
Subject: [PATCH 1/7] update tests, update code

---
 clang/include/clang/Basic/Attr.td             |   2 +-
 .../clang/Basic/DiagnosticSemaKinds.td        |   5 +-
 clang/include/clang/Sema/SemaHLSL.h           |   2 +
 clang/lib/Sema/HLSLExternalSemaSource.cpp     |  26 +-
 clang/lib/Sema/SemaHLSL.cpp                   | 232 +++++++++++++++++-
 .../ast-dump-comment-cbuffe-tbufferr.hlsl     |   2 +
 clang/test/AST/HLSL/cbuffer_tbuffer.hlsl      |   6 +-
 clang/test/AST/HLSL/packoffset.hlsl           |   1 +
 clang/test/AST/HLSL/pch_hlsl_buffer.hlsl      |   2 +
 .../test/AST/HLSL/resource_binding_attr.hlsl  |   6 +-
 .../SemaHLSL/resource_binding_attr_error.hlsl |  21 +-
 .../resource_binding_attr_error_mismatch.hlsl |  74 ++++++
 12 files changed, 346 insertions(+), 33 deletions(-)
 create mode 100644 clang/test/SemaHLSL/resource_binding_attr_error_mismatch.hlsl

diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td
index 452cd1810f653..c3d67e19656da 100644
--- a/clang/include/clang/Basic/Attr.td
+++ b/clang/include/clang/Basic/Attr.td
@@ -4467,7 +4467,7 @@ def HLSLSV_GroupIndex: HLSLAnnotationAttr {
 
 def HLSLResourceBinding: InheritableAttr {
   let Spellings = [HLSLAnnotation<"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/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 96f0c0f0205c2..3bf15ff5f2657 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -12303,7 +12303,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_unsupported_register_type : Error<"invalid resource class specifier '%0' used; expected 'b', 's', 't', or 'u'">;
+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_prefix : Error<"invalid resource class specifier '%0' used; expected 't', 'u', 'b', or 's'">;
+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 warn_hlsl_packoffset_mix : Warning<"cannot mix packoffset elements with nonpackoffset elements in a cbuffer">,
diff --git a/clang/include/clang/Sema/SemaHLSL.h b/clang/include/clang/Sema/SemaHLSL.h
index 4d6958a1be3e5..d3d36d04d1019 100644
--- a/clang/include/clang/Sema/SemaHLSL.h
+++ b/clang/include/clang/Sema/SemaHLSL.h
@@ -22,6 +22,7 @@
 #include "clang/Basic/SourceLocation.h"
 #include "clang/Sema/Scope.h"
 #include "clang/Sema/SemaBase.h"
+#include "clang/Sema/Sema.h"
 #include <initializer_list>
 
 namespace clang {
@@ -31,6 +32,7 @@ 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/HLSLExternalSemaSource.cpp b/clang/lib/Sema/HLSLExternalSemaSource.cpp
index a2b29a7bdf505..b82cd8373403a 100644
--- a/clang/lib/Sema/HLSLExternalSemaSource.cpp
+++ b/clang/lib/Sema/HLSLExternalSemaSource.cpp
@@ -490,23 +490,24 @@ 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) {
+static BuiltinTypeDeclBuilder setupBufferHandle(CXXRecordDecl *Decl, Sema &S,
+                                                ResourceClass RC) {
   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(*SemaPtr, {"element_type"})
-             .Record;
+  Decl =
+      BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "RWBuffer")
+          .addSimpleTemplateParams(*SemaPtr, {"element_type"})
+          .annotateResourceClass(ResourceClass::UAV, ResourceKind::TypedBuffer,
+                                 /*IsROV=*/false)
+          .Record;
+
   onCompletion(Decl, [this](CXXRecordDecl *Decl) {
-    setupBufferType(Decl, *SemaPtr, ResourceClass::UAV,
-                    ResourceKind::TypedBuffer, /*IsROV=*/false)
+    setupBufferHandle(Decl, *SemaPtr, ResourceClass::UAV)
         .addArraySubscriptOperators()
         .completeDefinition();
   });
@@ -514,10 +515,11 @@ void HLSLExternalSemaSource::defineHLSLTypesWithForwardDeclarations() {
   Decl =
       BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "RasterizerOrderedBuffer")
           .addSimpleTemplateParams(*SemaPtr, {"element_type"})
+          .annotateResourceClass(ResourceClass::UAV, ResourceKind::TypedBuffer,
+                                 /*IsROV=*/true)
           .Record;
   onCompletion(Decl, [this](CXXRecordDecl *Decl) {
-    setupBufferType(Decl, *SemaPtr, ResourceClass::UAV,
-                    ResourceKind::TypedBuffer, /*IsROV=*/true)
+    setupBufferHandle(Decl, *SemaPtr, ResourceClass::UAV)
         .addArraySubscriptOperators()
         .completeDefinition();
   });
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index eebe17a5b4bf7..d2b2f163231c9 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -29,6 +29,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,
@@ -38,6 +57,10 @@ Decl *SemaHLSL::ActOnStartBuffer(Scope *BufferScope, bool CBuffer,
   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);
 
@@ -437,7 +460,206 @@ void SemaHLSL::handleShaderAttr(Decl *D, const ParsedAttr &AL) {
     D->addAttr(NewAttr);
 }
 
+struct register_binding_flags {
+  bool resource = false;
+  bool udt = false;
+  bool other = false;
+  bool basic = false;
+
+  bool srv = false;
+  bool uav = false;
+  bool cbv = false;
+  bool sampler = false;
+
+  bool contains_numeric = false;
+  bool default_globals = false;
+};
+
+bool isDeclaredWithinCOrTBuffer(const Decl *decl) {
+  if (!decl)
+    return false;
+
+  // Traverse up the parent contexts
+  const DeclContext *context = decl->getDeclContext();
+  while (context) {
+    if (isa<HLSLBufferDecl>(context)) {
+      return true;
+    }
+    context = context->getParent();
+  }
+
+  return false;
+}
+
+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;
+  }
+
+  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;
+}
+
+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;
+      }     
+      }
+    }
+
+    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)) {
+    // 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;
+    }
+  }
+  // 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;
+      }      
+      }
+    } else {
+      if (SamplerUAVOrSRV->getType()->isBuiltinType())
+        r.basic = true;
+      else if (SamplerUAVOrSRV->getType()->isAggregateType()) {
+        r.udt = true;
+        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;
+    }
+  } else {
+    llvm_unreachable("unknown decl type");
+  }
+  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;
+
+  // TODO: emit diagnostic code based on the flags set in f.
+}
+
+
 void SemaHLSL::handleResourceBindingAttr(Decl *D, const ParsedAttr &AL) {
+  if (dyn_cast<VarDecl>(D)) {  
+    if (SemaRef.RequireCompleteType(D->getBeginLoc(), cast<ValueDecl>(D)->getType(),
+                              diag::err_incomplete_type))
+      return;
+  }
   StringRef Space = "space0";
   StringRef Slot = "";
 
@@ -470,13 +692,15 @@ void SemaHLSL::handleResourceBindingAttr(Decl *D, const ParsedAttr &AL) {
   // Validate.
   if (!Slot.empty()) {
     switch (Slot[0]) {
+    case 't':
     case 'u':
     case 'b':
     case 's':
-    case 't':
+    case 'c':
+    case 'i':
       break;
     default:
-      Diag(ArgLoc, diag::err_hlsl_unsupported_register_type)
+      Diag(ArgLoc, diag::err_hlsl_unsupported_register_prefix)
           << Slot.substr(0, 1);
       return;
     }
@@ -500,8 +724,8 @@ void SemaHLSL::handleResourceBindingAttr(Decl *D, const ParsedAttr &AL) {
     return;
   }
 
-  // FIXME: check reg type match decl. Issue
-  // https://github.com/llvm/llvm-project/issues/57886.
+  DiagnoseHLSLResourceRegType(SemaRef, ArgLoc, D, Slot);
+
   HLSLResourceBindingAttr *NewAttr =
       HLSLResourceBindingAttr::Create(getASTContext(), Slot, Space, AL);
   if (NewAttr)
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..727d505471bcb 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/packoffset.hlsl b/clang/test/AST/HLSL/packoffset.hlsl
index 060288c2f7f76..1dc99620c55c4 100644
--- a/clang/test/AST/HLSL/packoffset.hlsl
+++ b/clang/test/AST/HLSL/packoffset.hlsl
@@ -4,6 +4,7 @@
 // CHECK: HLSLBufferDecl {{.*}} cbuffer A
 cbuffer A
 {
+    // CHECK-NEXT:-HLSLResourceAttr {{.*}} <<invalid sloc>> line:5:9 cbuffer A
     // CHECK-NEXT: VarDecl {{.*}} A1 'float4'
     // CHECK-NEXT: HLSLPackOffsetAttr {{.*}} 0 0
     float4 A1 : packoffset(c);
diff --git a/clang/test/AST/HLSL/pch_hlsl_buffer.hlsl b/clang/test/AST/HLSL/pch_hlsl_buffer.hlsl
index e9a6ea1a16312..e264241e62e92 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 2f8aa098db701..58a1f3f1f64d7 100644
--- a/clang/test/SemaHLSL/resource_binding_attr_error.hlsl
+++ b/clang/test/SemaHLSL/resource_binding_attr_error.hlsl
@@ -1,9 +1,9 @@
 // RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -x hlsl -o - -fsyntax-only %s -verify
 
-// expected-error at +1 {{invalid resource class specifier 'c' used; expected 'b', 's', 't', or 'u'}}
+// FIXME: emit a diagnostic because float doesn't match the 'c' register type
 float a : register(c0, space1);
 
-// expected-error at +1 {{invalid resource class specifier 'i' used; expected 'b', 's', 't', or 'u'}}
+// FIXME: emit a diagnostic because cbuffer doesn't match the 'i' register type
 cbuffer b : register(i0) {
 
 }
@@ -33,28 +33,27 @@ cbuffer C : register(b 2) {}
 // expected-error at +1 {{wrong argument format for hlsl attribute, use space3 instead}}
 cbuffer D : register(b 2, space 3) {}
 
-// expected-warning at +1 {{'register' attribute only applies to cbuffer/tbuffer and external global variables}}
+// expected-error at +1 {{'register' attribute only applies to cbuffer/tbuffer and external global variables}}
 static RWBuffer<float> U : register(u5);
 
 void foo() {
-  // expected-warning at +1 {{'register' attribute only applies to cbuffer/tbuffer and external global variables}}
+  // expected-error at +1 {{'register' attribute only applies to cbuffer/tbuffer and external global variables}}
   RWBuffer<float> U : register(u3);
 }
 void foo2() {
-  // expected-warning at +1 {{'register' attribute only applies to cbuffer/tbuffer and external global variables}}
+  // expected-error 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.
+
+// FIXME: emit a diagnostic because float doesn't match the 'u' register type
 float b : register(u0, space1);
 
-// expected-warning at +1 {{'register' attribute only applies to cbuffer/tbuffer and external global variables}}
+// expected-error at +1 {{'register' attribute only applies to cbuffer/tbuffer and external global variables}}
 void bar(RWBuffer<float> U : register(u3)) {
 
 }
 
-struct S {
-  // FIXME: generate better error when support semantic on struct field.
-  // See https://github.com/llvm/llvm-project/issues/57889.
-  // expected-warning at +1 {{'register' attribute only applies to cbuffer/tbuffer and external global variables}}
+struct S {  
+  // expected-error at +1 {{'register' attribute only applies to cbuffer/tbuffer and external global variables}}
   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
new file mode 100644
index 0000000000000..b47171f878436
--- /dev/null
+++ b/clang/test/SemaHLSL/resource_binding_attr_error_mismatch.hlsl
@@ -0,0 +1,74 @@
+// 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 resource type 'RWBuffer' (expected 'u')}}
+RWBuffer<int> a : register(b2, 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);
+
+// 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 'TextureCube' (expected 't')}}
+// NOT YET IMPLEMENTED TextureCube <float>  t8 : register(b8);
+
+// 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 'Texture1DArray' (expected 't')}}
+// NOT YET IMPLEMENTED Texture1DArray T1DArray_t2 : register(b2);
+
+// 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(u2, space2);
+
+// 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')}}
+// 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 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 resource type 'tbuffer' (expected 't')}}
+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 't')}}
+// NOT YET IMPLEMENTED FeedbackTexture2D<float> FBTex2D[3][] : register(u0, space26);
+
+// 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);
+
+
+// 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 8e20fce2dbb0e88bc6c286815d36339f37d34d80 Mon Sep 17 00:00:00 2001
From: Joshua Batista <jbatista at microsoft.com>
Date: Fri, 28 Jun 2024 16:18:43 -0700
Subject: [PATCH 2/7] remove mismatch test, will be applied in step 2 PR.
 update packoffset

---
 clang/test/AST/HLSL/packoffset.hlsl           |  2 +-
 .../resource_binding_attr_error_mismatch.hlsl | 74 -------------------
 2 files changed, 1 insertion(+), 75 deletions(-)
 delete mode 100644 clang/test/SemaHLSL/resource_binding_attr_error_mismatch.hlsl

diff --git a/clang/test/AST/HLSL/packoffset.hlsl b/clang/test/AST/HLSL/packoffset.hlsl
index 1dc99620c55c4..9deb63caa500a 100644
--- a/clang/test/AST/HLSL/packoffset.hlsl
+++ b/clang/test/AST/HLSL/packoffset.hlsl
@@ -4,7 +4,7 @@
 // CHECK: HLSLBufferDecl {{.*}} cbuffer A
 cbuffer A
 {
-    // CHECK-NEXT:-HLSLResourceAttr {{.*}} <<invalid sloc>> line:5:9 cbuffer A
+    // CHECK-NEXT:-HLSLResourceAttr {{.*}} <<invalid sloc>> Implicit CBuffer CBuffer
     // CHECK-NEXT: VarDecl {{.*}} A1 'float4'
     // CHECK-NEXT: HLSLPackOffsetAttr {{.*}} 0 0
     float4 A1 : packoffset(c);
diff --git a/clang/test/SemaHLSL/resource_binding_attr_error_mismatch.hlsl b/clang/test/SemaHLSL/resource_binding_attr_error_mismatch.hlsl
deleted file mode 100644
index b47171f878436..0000000000000
--- a/clang/test/SemaHLSL/resource_binding_attr_error_mismatch.hlsl
+++ /dev/null
@@ -1,74 +0,0 @@
-// 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 resource type 'RWBuffer' (expected 'u')}}
-RWBuffer<int> a : register(b2, 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);
-
-// 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 'TextureCube' (expected 't')}}
-// NOT YET IMPLEMENTED TextureCube <float>  t8 : register(b8);
-
-// 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 'Texture1DArray' (expected 't')}}
-// NOT YET IMPLEMENTED Texture1DArray T1DArray_t2 : register(b2);
-
-// 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(u2, space2);
-
-// 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')}}
-// 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 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 resource type 'tbuffer' (expected 't')}}
-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 't')}}
-// NOT YET IMPLEMENTED FeedbackTexture2D<float> FBTex2D[3][] : register(u0, space26);
-
-// 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);
-
-
-// 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 8e19f3dd702e0e65b991b2a741405c224a066ba0 Mon Sep 17 00:00:00 2001
From: Joshua Batista <jbatista at microsoft.com>
Date: Fri, 28 Jun 2024 16:29:20 -0700
Subject: [PATCH 3/7] clang-format

---
 clang/include/clang/Sema/SemaHLSL.h |  2 +-
 clang/lib/Sema/SemaHLSL.cpp         | 12 ++++++------
 2 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/clang/include/clang/Sema/SemaHLSL.h b/clang/include/clang/Sema/SemaHLSL.h
index d3d36d04d1019..4e2a93209386e 100644
--- a/clang/include/clang/Sema/SemaHLSL.h
+++ b/clang/include/clang/Sema/SemaHLSL.h
@@ -21,8 +21,8 @@
 #include "clang/Basic/IdentifierTable.h"
 #include "clang/Basic/SourceLocation.h"
 #include "clang/Sema/Scope.h"
-#include "clang/Sema/SemaBase.h"
 #include "clang/Sema/Sema.h"
+#include "clang/Sema/SemaBase.h"
 #include <initializer_list>
 
 namespace clang {
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index d2b2f163231c9..8b6ecc6b7d992 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -546,7 +546,7 @@ void traverseType(QualType T, register_binding_flags &r) {
       case llvm::hlsl::ResourceClass::Sampler: {
         r.sampler = true;
         break;
-      }     
+      }
       }
     }
 
@@ -617,7 +617,7 @@ register_binding_flags HLSLFillRegisterBindingFlags(Sema &S, Decl *D) {
       case llvm::hlsl::ResourceClass::Sampler: {
         r.sampler = true;
         break;
-      }      
+      }
       }
     } else {
       if (SamplerUAVOrSRV->getType()->isBuiltinType())
@@ -653,11 +653,11 @@ static void DiagnoseHLSLResourceRegType(Sema &S, SourceLocation &ArgLoc,
   // TODO: emit diagnostic code based on the flags set in f.
 }
 
-
 void SemaHLSL::handleResourceBindingAttr(Decl *D, const ParsedAttr &AL) {
-  if (dyn_cast<VarDecl>(D)) {  
-    if (SemaRef.RequireCompleteType(D->getBeginLoc(), cast<ValueDecl>(D)->getType(),
-                              diag::err_incomplete_type))
+  if (dyn_cast<VarDecl>(D)) {
+    if (SemaRef.RequireCompleteType(D->getBeginLoc(),
+                                    cast<ValueDecl>(D)->getType(),
+                                    diag::err_incomplete_type))
       return;
   }
   StringRef Space = "space0";

>From ba058afa3c79185396351cfe9d80ff6aa6ac3318 Mon Sep 17 00:00:00 2001
From: Joshua Batista <jbatista at microsoft.com>
Date: Mon, 1 Jul 2024 10:36:02 -0700
Subject: [PATCH 4/7] remove unnecessary header

---
 clang/include/clang/Sema/SemaHLSL.h | 1 -
 1 file changed, 1 deletion(-)

diff --git a/clang/include/clang/Sema/SemaHLSL.h b/clang/include/clang/Sema/SemaHLSL.h
index 4e2a93209386e..d72e136bd5457 100644
--- a/clang/include/clang/Sema/SemaHLSL.h
+++ b/clang/include/clang/Sema/SemaHLSL.h
@@ -21,7 +21,6 @@
 #include "clang/Basic/IdentifierTable.h"
 #include "clang/Basic/SourceLocation.h"
 #include "clang/Sema/Scope.h"
-#include "clang/Sema/Sema.h"
 #include "clang/Sema/SemaBase.h"
 #include <initializer_list>
 

>From c02869d8be071354dd26d3bb8af62056a0f3a2ee Mon Sep 17 00:00:00 2001
From: Joshua Batista <jbatista at microsoft.com>
Date: Mon, 1 Jul 2024 17:55:03 -0700
Subject: [PATCH 5/7] full implementation

---
 .../clang/Basic/DiagnosticSemaKinds.td        |  10 ++
 clang/lib/Sema/SemaHLSL.cpp                   | 162 +++++++++++++++++-
 2 files changed, 170 insertions(+), 2 deletions(-)

diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 3bf15ff5f2657..a4994922b15c9 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -12303,6 +12303,16 @@ 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_variable_type: Error<"unsupported resource register binding '%select{t|u|b|s}1' on variable of type '%0'">;
+def err_hlsl_unsupported_register_type_and_variable_type: Error<"register binding type '%1' not supported for variable of type '%0'">;
+def err_hlsl_mismatching_register_type_and_resource_type: Error<"%select{srv|uav|cbv|sampler}2 type '%0' requires register type '%select{t|u|b|s}2', but register type '%1' was used">;
+def err_hlsl_unsupported_register_type_and_resource_type: Error<"invalid register type '%0' used; expected 't', 'u', 'b', or 's'">;
+def err_hlsl_conflicting_register_annotations: Error<"conflicting register annotations: %0 and %0">;
+def warn_hlsl_deprecated_register_type_b: Warning<"deprecated legacy bool constant register binding 'b' used. 'b' is only used for constant buffer resource binding">;
+def warn_hlsl_deprecated_register_type_i: Warning<"deprecated legacy int constant register binding 'i' used">;
+def warn_hlsl_register_type_c_not_in_global_scope: Warning<"register binding 'c' ignored inside cbuffer/tbuffer declarations; use pack_offset instead">;
+def warn_hlsl_UDT_missing_resource_type_member: Warning<"variable of type '%0' bound to register type '%1' does not contain a matching '%select{srv|uav|cbv|sampler}2' resource">;
+def warn_hlsl_UDT_missing_basic_type: Warning<"register 'c' used on type with no contents to allocate in a constant buffer">;
 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_prefix : Error<"invalid resource class specifier '%0' used; expected 't', 'u', 'b', or 's'">;
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index 8b6ecc6b7d992..0cdce9e53bd93 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -639,10 +639,26 @@ register_binding_flags HLSLFillRegisterBindingFlags(Sema &S, Decl *D) {
   return r;
 }
 
+static void ValidateMultipleRegisterAnnotations(Sema &S, Decl *D,
+                                                StringRef &Slot) {
+  std::set<std::string> s; // store unique register type + numbers
+  for (auto it = D->attr_begin(); it != D->attr_end(); ++it) {
+    
+    if (HLSLResourceBindingAttr *attr =
+            dyn_cast<HLSLResourceBindingAttr>(*it)) {
+      std::string regInfo(Slot);   
+      auto p = s.insert(regInfo);
+      if (!p.second) {
+        S.Diag(attr->getLoc(), diag::err_hlsl_conflicting_register_annotations)
+            << Slot.substr(0, 1);
+      }
+    }
+  }
+}
+
 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
@@ -650,7 +666,149 @@ static void DiagnoseHLSLResourceRegType(Sema &S, SourceLocation &ArgLoc,
   if (!SamplerUAVOrSRV && !CBufferOrTBuffer)
     return;
 
-  // TODO: emit diagnostic code based on the flags set in f.
+  register_binding_flags f = HLSLFillRegisterBindingFlags(S, D);
+  assert((int)f.other + (int)f.resource + (int)f.basic + (int)f.udt == 1 && "only one resource analysis result should be expected");
+
+  // get the variable type
+  std::string typestr;
+  if (SamplerUAVOrSRV) {
+    QualType QT = SamplerUAVOrSRV->getType();
+    PrintingPolicy PP = S.getPrintingPolicy();
+    typestr = QualType::getAsString(QT.split(), PP);
+  } else 
+    typestr = CBufferOrTBuffer->isCBuffer() ? "cbuffer" : "tbuffer";
+  
+
+  // first, if "other" is set, emit an error
+  if (f.other) {  
+    S.Diag(ArgLoc, diag::err_hlsl_unsupported_register_type_and_variable_type)
+        << Slot << typestr;
+  }
+
+  // next, if multiple register annotations exist, check that none conflict.
+  ValidateMultipleRegisterAnnotations(S, D, Slot);
+  
+  // next, if resource is set, make sure the register type in the register annotation
+  // is compatible with the variable's resource type.
+  if (f.resource) {
+    VarDecl *VD = dyn_cast<VarDecl>(D);
+
+    const HLSLResourceAttr *res_attr =
+        getHLSLResourceAttrFromVarDecl(VD);
+    assert(res_attr && "any decl that set the resource flag on analysis should have a resource attribute attached.");
+    llvm::hlsl::ResourceClass DeclResourceClass = res_attr->getResourceClass();
+    switch (DeclResourceClass) {
+    case llvm::hlsl::ResourceClass::SRV: {
+      if (!f.srv) {
+        S.Diag(
+            res_attr->getLoc(), diag::err_hlsl_mismatching_register_type_and_resource_type)
+            << typestr << Slot[0] << 0 /*srv*/;
+      }
+      break;
+    }
+    case llvm::hlsl::ResourceClass::UAV: {
+      if (!f.uav) {
+        S.Diag(res_attr->getLoc(),
+               diag::err_hlsl_mismatching_register_type_and_resource_type)
+            << typestr << Slot[0] << 1 /*uav*/;
+      }
+      break;
+    }
+    case llvm::hlsl::ResourceClass::CBuffer: {
+      if (!f.cbv) {
+        S.Diag(res_attr->getLoc(),
+               diag::err_hlsl_mismatching_register_type_and_resource_type)
+            << typestr << Slot[0] << 2 /*cbv*/;
+      }
+      break;
+    }
+    case llvm::hlsl::ResourceClass::Sampler: {
+      if (!f.sampler) {
+        S.Diag(res_attr->getLoc(),
+               diag::err_hlsl_mismatching_register_type_and_resource_type)
+            << typestr << Slot[0] << 3 /*sampler*/;
+      }
+      break;
+    }
+    }
+  }
+  
+  // next, handle diagnostics for when the "basic" flag is set,
+  // including the legacy "i" and "b" register types.
+  if (f.basic) {
+    if (f.default_globals) {
+      if (Slot[0] == 'b')
+        S.Diag(ArgLoc, diag::warn_hlsl_deprecated_register_type_b);      
+      if (Slot[0] == 'i')
+        S.Diag(ArgLoc, diag::warn_hlsl_deprecated_register_type_i);      
+    }
+
+    else if (Slot[0] == 'c') {
+      if (!f.default_globals){
+        S.Diag(ArgLoc, diag::warn_hlsl_register_type_c_not_in_global_scope);
+      }      
+    } 
+    else if (Slot[0] == 't')
+        S.Diag(ArgLoc, diag::err_hlsl_mismatching_register_type_and_variable_type) << 0 << typestr;
+    else if (Slot[0] == 'u')
+      S.Diag(ArgLoc,
+              diag::err_hlsl_mismatching_register_type_and_variable_type)
+          << 1 << typestr;
+    else if (Slot[0] == 's')
+      S.Diag(ArgLoc,
+              diag::err_hlsl_mismatching_register_type_and_variable_type)
+          << 3 << typestr;
+    // any other register type should emit err_hlsl_unsupported_register_type_and_variable_type
+    else {
+      S.Diag(ArgLoc, diag::err_hlsl_unsupported_register_type_and_variable_type)
+          << Slot[0] << typestr;
+    }    
+  }
+
+  // finally, we handle the udt case
+  
+  if (f.udt) {
+    for (auto it = D->attr_begin(); it != D->attr_end(); ++it) {
+      if (HLSLResourceBindingAttr *attr =
+              dyn_cast<HLSLResourceBindingAttr>(*it)) {
+        llvm::StringRef registerTypeSlotRef = attr->getSlot();
+        std::string registerTypeSlot(
+            registerTypeSlotRef);
+        if (registerTypeSlot[0] == 't') {        
+          if (!f.srv) {
+            S.Diag(attr->getLoc(),
+                   diag::warn_hlsl_UDT_missing_resource_type_member)
+                << typestr << "t"
+                << 0;
+          }
+        } else if (registerTypeSlot[0] == 'u') {
+          if (!f.uav) {
+            S.Diag(attr->getLoc(),
+                   diag::warn_hlsl_UDT_missing_resource_type_member)
+                << typestr << "u" << 1;
+          }
+        } else if (registerTypeSlot[0] == 'b') {
+          if (!f.cbv) {
+            S.Diag(attr->getLoc(), diag::warn_hlsl_UDT_missing_resource_type_member)
+                << typestr << "b" << 2;
+          }
+        } else if (registerTypeSlot[0] == 's') {
+          if (!f.sampler) {
+            S.Diag(attr->getLoc(), diag::warn_hlsl_UDT_missing_resource_type_member)
+                << typestr << "s" << 3;
+          }
+        } else if (registerTypeSlot[0] == 'c') {
+          if (!f.srv)
+            S.Diag(attr->getLoc(), diag::warn_hlsl_UDT_missing_basic_type);          
+        } 
+        else {
+          S.Diag(attr->getLoc(),
+                 diag::err_hlsl_unsupported_register_type_and_variable_type)
+              << registerTypeSlot[0] << typestr;
+        }
+      }
+    }
+  } 
 }
 
 void SemaHLSL::handleResourceBindingAttr(Decl *D, const ParsedAttr &AL) {

>From b75f9fb7356b9c4539cad609957b4f2773c42216 Mon Sep 17 00:00:00 2001
From: Joshua Batista <jbatista at microsoft.com>
Date: Mon, 1 Jul 2024 17:55:33 -0700
Subject: [PATCH 6/7] clang format

---
 clang/lib/Sema/SemaHLSL.cpp | 74 ++++++++++++++++++-------------------
 1 file changed, 36 insertions(+), 38 deletions(-)

diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index 0cdce9e53bd93..8cd793ceff4c9 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -667,7 +667,8 @@ static void DiagnoseHLSLResourceRegType(Sema &S, SourceLocation &ArgLoc,
     return;
 
   register_binding_flags f = HLSLFillRegisterBindingFlags(S, D);
-  assert((int)f.other + (int)f.resource + (int)f.basic + (int)f.udt == 1 && "only one resource analysis result should be expected");
+  assert((int)f.other + (int)f.resource + (int)f.basic + (int)f.udt == 1 &&
+         "only one resource analysis result should be expected");
 
   // get the variable type
   std::string typestr;
@@ -675,33 +676,32 @@ static void DiagnoseHLSLResourceRegType(Sema &S, SourceLocation &ArgLoc,
     QualType QT = SamplerUAVOrSRV->getType();
     PrintingPolicy PP = S.getPrintingPolicy();
     typestr = QualType::getAsString(QT.split(), PP);
-  } else 
+  } else
     typestr = CBufferOrTBuffer->isCBuffer() ? "cbuffer" : "tbuffer";
-  
 
   // first, if "other" is set, emit an error
-  if (f.other) {  
+  if (f.other) {
     S.Diag(ArgLoc, diag::err_hlsl_unsupported_register_type_and_variable_type)
         << Slot << typestr;
   }
 
   // next, if multiple register annotations exist, check that none conflict.
   ValidateMultipleRegisterAnnotations(S, D, Slot);
-  
-  // next, if resource is set, make sure the register type in the register annotation
-  // is compatible with the variable's resource type.
+
+  // next, if resource is set, make sure the register type in the register
+  // annotation is compatible with the variable's resource type.
   if (f.resource) {
     VarDecl *VD = dyn_cast<VarDecl>(D);
 
-    const HLSLResourceAttr *res_attr =
-        getHLSLResourceAttrFromVarDecl(VD);
-    assert(res_attr && "any decl that set the resource flag on analysis should have a resource attribute attached.");
+    const HLSLResourceAttr *res_attr = getHLSLResourceAttrFromVarDecl(VD);
+    assert(res_attr && "any decl that set the resource flag on analysis should "
+                       "have a resource attribute attached.");
     llvm::hlsl::ResourceClass DeclResourceClass = res_attr->getResourceClass();
     switch (DeclResourceClass) {
     case llvm::hlsl::ResourceClass::SRV: {
       if (!f.srv) {
-        S.Diag(
-            res_attr->getLoc(), diag::err_hlsl_mismatching_register_type_and_resource_type)
+        S.Diag(res_attr->getLoc(),
+               diag::err_hlsl_mismatching_register_type_and_resource_type)
             << typestr << Slot[0] << 0 /*srv*/;
       }
       break;
@@ -732,54 +732,51 @@ static void DiagnoseHLSLResourceRegType(Sema &S, SourceLocation &ArgLoc,
     }
     }
   }
-  
+
   // next, handle diagnostics for when the "basic" flag is set,
   // including the legacy "i" and "b" register types.
   if (f.basic) {
     if (f.default_globals) {
       if (Slot[0] == 'b')
-        S.Diag(ArgLoc, diag::warn_hlsl_deprecated_register_type_b);      
+        S.Diag(ArgLoc, diag::warn_hlsl_deprecated_register_type_b);
       if (Slot[0] == 'i')
-        S.Diag(ArgLoc, diag::warn_hlsl_deprecated_register_type_i);      
+        S.Diag(ArgLoc, diag::warn_hlsl_deprecated_register_type_i);
     }
 
     else if (Slot[0] == 'c') {
-      if (!f.default_globals){
+      if (!f.default_globals) {
         S.Diag(ArgLoc, diag::warn_hlsl_register_type_c_not_in_global_scope);
-      }      
-    } 
-    else if (Slot[0] == 't')
-        S.Diag(ArgLoc, diag::err_hlsl_mismatching_register_type_and_variable_type) << 0 << typestr;
+      }
+    } else if (Slot[0] == 't')
+      S.Diag(ArgLoc, diag::err_hlsl_mismatching_register_type_and_variable_type)
+          << 0 << typestr;
     else if (Slot[0] == 'u')
-      S.Diag(ArgLoc,
-              diag::err_hlsl_mismatching_register_type_and_variable_type)
+      S.Diag(ArgLoc, diag::err_hlsl_mismatching_register_type_and_variable_type)
           << 1 << typestr;
     else if (Slot[0] == 's')
-      S.Diag(ArgLoc,
-              diag::err_hlsl_mismatching_register_type_and_variable_type)
+      S.Diag(ArgLoc, diag::err_hlsl_mismatching_register_type_and_variable_type)
           << 3 << typestr;
-    // any other register type should emit err_hlsl_unsupported_register_type_and_variable_type
+    // any other register type should emit
+    // err_hlsl_unsupported_register_type_and_variable_type
     else {
       S.Diag(ArgLoc, diag::err_hlsl_unsupported_register_type_and_variable_type)
           << Slot[0] << typestr;
-    }    
+    }
   }
 
   // finally, we handle the udt case
-  
+
   if (f.udt) {
     for (auto it = D->attr_begin(); it != D->attr_end(); ++it) {
       if (HLSLResourceBindingAttr *attr =
               dyn_cast<HLSLResourceBindingAttr>(*it)) {
         llvm::StringRef registerTypeSlotRef = attr->getSlot();
-        std::string registerTypeSlot(
-            registerTypeSlotRef);
-        if (registerTypeSlot[0] == 't') {        
+        std::string registerTypeSlot(registerTypeSlotRef);
+        if (registerTypeSlot[0] == 't') {
           if (!f.srv) {
             S.Diag(attr->getLoc(),
                    diag::warn_hlsl_UDT_missing_resource_type_member)
-                << typestr << "t"
-                << 0;
+                << typestr << "t" << 0;
           }
         } else if (registerTypeSlot[0] == 'u') {
           if (!f.uav) {
@@ -789,26 +786,27 @@ static void DiagnoseHLSLResourceRegType(Sema &S, SourceLocation &ArgLoc,
           }
         } else if (registerTypeSlot[0] == 'b') {
           if (!f.cbv) {
-            S.Diag(attr->getLoc(), diag::warn_hlsl_UDT_missing_resource_type_member)
+            S.Diag(attr->getLoc(),
+                   diag::warn_hlsl_UDT_missing_resource_type_member)
                 << typestr << "b" << 2;
           }
         } else if (registerTypeSlot[0] == 's') {
           if (!f.sampler) {
-            S.Diag(attr->getLoc(), diag::warn_hlsl_UDT_missing_resource_type_member)
+            S.Diag(attr->getLoc(),
+                   diag::warn_hlsl_UDT_missing_resource_type_member)
                 << typestr << "s" << 3;
           }
         } else if (registerTypeSlot[0] == 'c') {
           if (!f.srv)
-            S.Diag(attr->getLoc(), diag::warn_hlsl_UDT_missing_basic_type);          
-        } 
-        else {
+            S.Diag(attr->getLoc(), diag::warn_hlsl_UDT_missing_basic_type);
+        } else {
           S.Diag(attr->getLoc(),
                  diag::err_hlsl_unsupported_register_type_and_variable_type)
               << registerTypeSlot[0] << typestr;
         }
       }
     }
-  } 
+  }
 }
 
 void SemaHLSL::handleResourceBindingAttr(Decl *D, const ParsedAttr &AL) {

>From a2bf4416ed91cf9ab408b6fb773fcc2e5c528696 Mon Sep 17 00:00:00 2001
From: Joshua Batista <jbatista at microsoft.com>
Date: Tue, 2 Jul 2024 16:41:39 -0700
Subject: [PATCH 7/7] fix mismatching register type diagnostic logic

---
 clang/lib/Sema/SemaHLSL.cpp                   | 113 ++++++++++--------
 .../SemaHLSL/resource_binding_attr_error.hlsl |   7 +-
 .../resource_binding_attr_error_mismatch.hlsl |  74 ++++++++++++
 3 files changed, 142 insertions(+), 52 deletions(-)
 create mode 100644 clang/test/SemaHLSL/resource_binding_attr_error_mismatch.hlsl

diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index 8cd793ceff4c9..1d1ced083b1d3 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -492,31 +492,39 @@ bool isDeclaredWithinCOrTBuffer(const Decl *decl) {
 }
 
 const HLSLResourceAttr *
-getHLSLResourceAttrFromVarDecl(VarDecl *SamplerUAVOrSRV) {
-  const Type *Ty = SamplerUAVOrSRV->getType()->getPointeeOrArrayElementType();
-  if (!Ty)
-    llvm_unreachable("Resource class must have an element type.");
+getHLSLResourceAttrFromEitherDecl(VarDecl *SamplerUAVOrSRV,
+                                  HLSLBufferDecl *CBufferOrTBuffer) {
 
-  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;
-  }
+  if (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;
+    }
 
-  const CXXRecordDecl *TheRecordDecl = Ty->getAsCXXRecordDecl();
-  if (!TheRecordDecl)
-    llvm_unreachable("Resource class should have a resource type declaration.");
+    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;
+    if (auto TDecl = dyn_cast<ClassTemplateSpecializationDecl>(TheRecordDecl))
+      TheRecordDecl = TDecl->getSpecializedTemplate()->getTemplatedDecl();
+    TheRecordDecl = TheRecordDecl->getCanonicalDecl();
+    const auto *Attr = TheRecordDecl->getAttr<HLSLResourceAttr>();
+    return Attr;
+  } else if (CBufferOrTBuffer) {
+    const auto *Attr = CBufferOrTBuffer->getAttr<HLSLResourceAttr>();
+    return Attr;
+  }
 }
 
 void traverseType(QualType T, register_binding_flags &r) {
@@ -596,7 +604,7 @@ register_binding_flags HLSLFillRegisterBindingFlags(Sema &S, Decl *D) {
       r.srv = true;
   } else if (SamplerUAVOrSRV) {
     const HLSLResourceAttr *res_attr =
-        getHLSLResourceAttrFromVarDecl(SamplerUAVOrSRV);
+        getHLSLResourceAttrFromEitherDecl(SamplerUAVOrSRV, CBufferOrTBuffer);
     if (res_attr) {
       llvm::hlsl::ResourceClass DeclResourceClass =
           res_attr->getResourceClass();
@@ -663,8 +671,12 @@ static void DiagnoseHLSLResourceRegType(Sema &S, SourceLocation &ArgLoc,
   VarDecl *SamplerUAVOrSRV = dyn_cast<VarDecl>(D);
   // Cbuffers and Tbuffers are HLSLBufferDecl types
   HLSLBufferDecl *CBufferOrTBuffer = dyn_cast<HLSLBufferDecl>(D);
+
+  // exactly one of these two types should be set
   if (!SamplerUAVOrSRV && !CBufferOrTBuffer)
     return;
+  if (SamplerUAVOrSRV && CBufferOrTBuffer)
+    return;
 
   register_binding_flags f = HLSLFillRegisterBindingFlags(S, D);
   assert((int)f.other + (int)f.resource + (int)f.basic + (int)f.udt == 1 &&
@@ -679,6 +691,8 @@ static void DiagnoseHLSLResourceRegType(Sema &S, SourceLocation &ArgLoc,
   } else
     typestr = CBufferOrTBuffer->isCBuffer() ? "cbuffer" : "tbuffer";
 
+  std::string registerType(Slot.substr(0, 1));
+
   // first, if "other" is set, emit an error
   if (f.other) {
     S.Diag(ArgLoc, diag::err_hlsl_unsupported_register_type_and_variable_type)
@@ -691,42 +705,43 @@ static void DiagnoseHLSLResourceRegType(Sema &S, SourceLocation &ArgLoc,
   // next, if resource is set, make sure the register type in the register
   // annotation is compatible with the variable's resource type.
   if (f.resource) {
-    VarDecl *VD = dyn_cast<VarDecl>(D);
-
-    const HLSLResourceAttr *res_attr = getHLSLResourceAttrFromVarDecl(VD);
+    const HLSLResourceAttr *res_attr =
+        getHLSLResourceAttrFromEitherDecl(SamplerUAVOrSRV, CBufferOrTBuffer);
     assert(res_attr && "any decl that set the resource flag on analysis should "
                        "have a resource attribute attached.");
-    llvm::hlsl::ResourceClass DeclResourceClass = res_attr->getResourceClass();
+    const llvm::hlsl::ResourceClass DeclResourceClass =
+        res_attr->getResourceClass();
+
     switch (DeclResourceClass) {
     case llvm::hlsl::ResourceClass::SRV: {
-      if (!f.srv) {
-        S.Diag(res_attr->getLoc(),
+      if (registerType != "t") {
+        S.Diag(D->getLocation(),
                diag::err_hlsl_mismatching_register_type_and_resource_type)
-            << typestr << Slot[0] << 0 /*srv*/;
+            << typestr << registerType << 0 /*srv*/;
       }
       break;
     }
     case llvm::hlsl::ResourceClass::UAV: {
-      if (!f.uav) {
-        S.Diag(res_attr->getLoc(),
+      if (registerType != "u") {
+        S.Diag(D->getLocation(),
                diag::err_hlsl_mismatching_register_type_and_resource_type)
-            << typestr << Slot[0] << 1 /*uav*/;
+            << typestr << registerType << 1 /*uav*/;
       }
       break;
     }
     case llvm::hlsl::ResourceClass::CBuffer: {
-      if (!f.cbv) {
-        S.Diag(res_attr->getLoc(),
+      if (registerType != "b") {
+        S.Diag(D->getLocation(),
                diag::err_hlsl_mismatching_register_type_and_resource_type)
-            << typestr << Slot[0] << 2 /*cbv*/;
+            << typestr << registerType << 2 /*cbv*/;
       }
       break;
     }
     case llvm::hlsl::ResourceClass::Sampler: {
-      if (!f.sampler) {
-        S.Diag(res_attr->getLoc(),
+      if (registerType != "s") {
+        S.Diag(D->getLocation(),
                diag::err_hlsl_mismatching_register_type_and_resource_type)
-            << typestr << Slot[0] << 3 /*sampler*/;
+            << typestr << registerType << 3 /*sampler*/;
       }
       break;
     }
@@ -747,18 +762,18 @@ static void DiagnoseHLSLResourceRegType(Sema &S, SourceLocation &ArgLoc,
       if (!f.default_globals) {
         S.Diag(ArgLoc, diag::warn_hlsl_register_type_c_not_in_global_scope);
       }
-    } else if (Slot[0] == 't')
+    } else if (Slot[0] == 't') {
       S.Diag(ArgLoc, diag::err_hlsl_mismatching_register_type_and_variable_type)
           << 0 << typestr;
-    else if (Slot[0] == 'u')
+    } else if (Slot[0] == 'u') {
       S.Diag(ArgLoc, diag::err_hlsl_mismatching_register_type_and_variable_type)
           << 1 << typestr;
-    else if (Slot[0] == 's')
+    } else if (Slot[0] == 's') {
       S.Diag(ArgLoc, diag::err_hlsl_mismatching_register_type_and_variable_type)
           << 3 << typestr;
     // any other register type should emit
     // err_hlsl_unsupported_register_type_and_variable_type
-    else {
+    } else {
       S.Diag(ArgLoc, diag::err_hlsl_unsupported_register_type_and_variable_type)
           << Slot[0] << typestr;
     }
@@ -772,37 +787,37 @@ static void DiagnoseHLSLResourceRegType(Sema &S, SourceLocation &ArgLoc,
               dyn_cast<HLSLResourceBindingAttr>(*it)) {
         llvm::StringRef registerTypeSlotRef = attr->getSlot();
         std::string registerTypeSlot(registerTypeSlotRef);
-        if (registerTypeSlot[0] == 't') {
+        if (registerTypeSlot.front() == 't') {
           if (!f.srv) {
             S.Diag(attr->getLoc(),
                    diag::warn_hlsl_UDT_missing_resource_type_member)
                 << typestr << "t" << 0;
           }
-        } else if (registerTypeSlot[0] == 'u') {
+        } else if (registerTypeSlot.front() == 'u') {
           if (!f.uav) {
             S.Diag(attr->getLoc(),
                    diag::warn_hlsl_UDT_missing_resource_type_member)
                 << typestr << "u" << 1;
           }
-        } else if (registerTypeSlot[0] == 'b') {
+        } else if (registerTypeSlot.front() == 'b') {
           if (!f.cbv) {
             S.Diag(attr->getLoc(),
                    diag::warn_hlsl_UDT_missing_resource_type_member)
                 << typestr << "b" << 2;
           }
-        } else if (registerTypeSlot[0] == 's') {
+        } else if (registerTypeSlot.front() == 's') {
           if (!f.sampler) {
             S.Diag(attr->getLoc(),
                    diag::warn_hlsl_UDT_missing_resource_type_member)
                 << typestr << "s" << 3;
           }
-        } else if (registerTypeSlot[0] == 'c') {
+        } else if (registerTypeSlot.front() == 'c') {
           if (!f.srv)
             S.Diag(attr->getLoc(), diag::warn_hlsl_UDT_missing_basic_type);
         } else {
           S.Diag(attr->getLoc(),
                  diag::err_hlsl_unsupported_register_type_and_variable_type)
-              << registerTypeSlot[0] << typestr;
+              << registerTypeSlot.front() << typestr;
         }
       }
     }
diff --git a/clang/test/SemaHLSL/resource_binding_attr_error.hlsl b/clang/test/SemaHLSL/resource_binding_attr_error.hlsl
index 58a1f3f1f64d7..ce81574a79608 100644
--- a/clang/test/SemaHLSL/resource_binding_attr_error.hlsl
+++ b/clang/test/SemaHLSL/resource_binding_attr_error.hlsl
@@ -1,9 +1,10 @@
 // RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -x hlsl -o - -fsyntax-only %s -verify
 
-// FIXME: emit a diagnostic because float doesn't match the 'c' register type
-float a : register(c0, space1);
+// valid, The register keyword in this statement isn't binding a resource, rather it is
+// specifying a constant register binding offset within the $Globals cbuffer, which is legacy behavior from DX9.
+float a : register(c0);
 
-// FIXME: emit a diagnostic because cbuffer doesn't match the 'i' register type
+// expected-error at +1 {{cbv type 'cbuffer' requires register type 'b', but register type 'i' was used}}
 cbuffer b : register(i0) {
 
 }
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..54e852483f832
--- /dev/null
+++ b/clang/test/SemaHLSL/resource_binding_attr_error_mismatch.hlsl
@@ -0,0 +1,74 @@
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -x hlsl -o - -fsyntax-only %s -verify
+
+
+// expected-error at +1  {{uav type 'RWBuffer<int>' requires register type 'u', but register type 'b' was used}}
+RWBuffer<int> a : register(b2, space1);
+
+// expected-error at +1  {{uav type 'RWBuffer<int>' requires register type 'u', but register type 't' was used}}
+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 'TextureCube' (expected 't')}}
+// NOT YET IMPLEMENTED TextureCube <float>  t8 : register(b8);
+
+// 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 'Texture1DArray' (expected 't')}}
+// NOT YET IMPLEMENTED Texture1DArray T1DArray_t2 : register(b2);
+
+// 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(u2, space2);
+
+// 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')}}
+// 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 {{cbv type 'cbuffer' requires register type 'b', but register type 's' was used}}
+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 {{srv type 'tbuffer' requires register type 't', but register type 's' was used}}
+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 't')}}
+// NOT YET IMPLEMENTED FeedbackTexture2D<float> FBTex2D[3][] : register(u0, space26);
+
+// 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);
+
+
+// empty binding prefix cases:
+// expected-error at +1 {{expected identifier}}
+RWBuffer<int> c: register();
+
+// expected-error at +1 {{expected identifier}}
+RWBuffer<int> d: register("");



More information about the cfe-commits mailing list