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

Justin Bogner via cfe-commits cfe-commits at lists.llvm.org
Wed Apr 24 12:35:51 PDT 2024


================
@@ -7334,6 +7334,100 @@ 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 {
+    if (CBufferOrTBuffer->isCBuffer()) {
+      DeclResourceClass = llvm::hlsl::ResourceClass::CBuffer;
+      VarTy = "cbuffer";
+    } else {
+      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_resource_type_and_name)
+          << Slot.substr(0, 1) << VarTy
+          << (unsigned)llvm::hlsl::ResourceClass::SRV;
+    break;
----------------
bogner wrote:

This code is all a little repetitive. Should we reverse the logic and exit early in the valid cases instead, and emit the diagnostic in the fallthrough?

```c++
  switch (DeclResourceClass) {
  case llvm::hlsl::ResourceClass::SRV:
    if (Slot[0] == 't')
      return;
  case llvm::hlsl::ResourceClass::UAV:
    if (Slot[0] == 'u')
      return;
  // ...
  }
  S.Diag(ArgLoc, diag::err_hlsl_mismatching_register_resource_type_and_name)
      << Slot.substr(0, 1) << VarTy
      << (unsigned)DeclResourceClass;
```

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


More information about the cfe-commits mailing list