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

Justin Bogner via llvm-commits llvm-commits at lists.llvm.org
Mon Apr 29 11:04:54 PDT 2024


================
@@ -7334,6 +7334,92 @@ 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.");
+
+    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] != 't')
+        S.Diag(ArgLoc,
+               diag::err_hlsl_mismatching_register_builtin_type_and_name)
+            << Slot.substr(0, 1) << typestr << "'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>();
+    if (!Attr)
+      llvm_unreachable("Resource class should have a resource attribute.");
+
+    DeclResourceClass = Attr->getResourceClass();
+    VarTy = TheRecordDecl->getName();
+  } else {
+    DeclResourceClass = llvm::hlsl::ResourceClass::CBuffer;
+  }
+  switch (DeclResourceClass) {
+  case llvm::hlsl::ResourceClass::SRV: {
+    if (Slot[0] == 't')
+      return;
+    break;
+  }
+  case llvm::hlsl::ResourceClass::UAV: {
+    if (Slot[0] == 'u')
+      return;
+    break;
+  }
+  case llvm::hlsl::ResourceClass::CBuffer: {
+    // 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;
----------------
bogner wrote:

This comment isn't exactly correct. A `tbuffer` *is* an SRV, we simply don't have a `ClassDecl` with the annotation to get that information from. I wonder if it would be better to put attributes on `HLSLBufferDecl` (perhaps in `SemaHLSL::ActOnStartBuffer`) so that we can drive the two ways of getting here in the same way.

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


More information about the llvm-commits mailing list