[clang] [HLSL] Apply resource attributes to the resource type rather than the handle member (PR #107160)

Helena Kotas via cfe-commits cfe-commits at lists.llvm.org
Thu Sep 5 12:23:08 PDT 2024


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

>From 337a9ed1d5e7c71fb5be5741afe7726f5b76af7b Mon Sep 17 00:00:00 2001
From: Helena Kotas <hekotas at microsoft.com>
Date: Tue, 3 Sep 2024 15:30:50 -0700
Subject: [PATCH 1/6] [HLSL] Apply resource attributes to the resource type
 rather than the handle member (#6)

---
 clang/include/clang/AST/TypeLoc.h             |   8 +
 clang/include/clang/Basic/Attr.td             |   6 +-
 .../clang/Basic/DiagnosticSemaKinds.td        |   1 +
 clang/include/clang/Sema/SemaHLSL.h           |  21 ++-
 clang/lib/AST/TypePrinter.cpp                 |   9 +-
 clang/lib/CodeGen/CGHLSLRuntime.cpp           |  10 +-
 clang/lib/Sema/HLSLExternalSemaSource.cpp     |  25 ++-
 clang/lib/Sema/SemaDeclAttr.cpp               |   6 -
 clang/lib/Sema/SemaHLSL.cpp                   | 177 ++++++++++++------
 clang/lib/Sema/TreeTransform.h                |  22 ++-
 clang/test/AST/HLSL/RWBuffer-AST.hlsl         |  10 +-
 ...a-attribute-supported-attributes-list.test |   2 -
 clang/test/ParserHLSL/hlsl_is_rov_attr.hlsl   |  17 +-
 .../ParserHLSL/hlsl_is_rov_attr_error.hlsl    |  21 ++-
 .../ParserHLSL/hlsl_resource_class_attr.hlsl  |  48 ++---
 .../hlsl_resource_class_attr_error.hlsl       |  29 +--
 .../hlsl_resource_handle_attrs.hlsl           |  17 +-
 .../SemaHLSL/resource_binding_attr_error.hlsl |   2 +-
 .../resource_binding_attr_error_resource.hlsl |  10 +-
 .../resource_binding_attr_error_udt.hlsl      |  10 +-
 20 files changed, 284 insertions(+), 167 deletions(-)

diff --git a/clang/include/clang/AST/TypeLoc.h b/clang/include/clang/AST/TypeLoc.h
index 5db39eb3aefa74..03fbdcf60140df 100644
--- a/clang/include/clang/AST/TypeLoc.h
+++ b/clang/include/clang/AST/TypeLoc.h
@@ -951,12 +951,20 @@ class HLSLAttributedResourceTypeLoc
                              HLSLAttributedResourceLocInfo> {
 public:
   TypeLoc getWrappedLoc() const { return getInnerTypeLoc(); }
+
+  TypeLoc getContainedLoc() const {
+    return TypeLoc(getTypePtr()->getContainedType(), getNonLocalData());
+  }
+
   void setSourceRange(const SourceRange &R) { getLocalData()->Range = R; }
   SourceRange getLocalSourceRange() const { return getLocalData()->Range; }
   void initializeLocal(ASTContext &Context, SourceLocation loc) {
     setSourceRange(SourceRange());
   }
   QualType getInnerType() const { return getTypePtr()->getWrappedType(); }
+  unsigned getLocalDataSize() const {
+    return sizeof(HLSLAttributedResourceLocInfo);
+  }
 };
 
 struct ObjCObjectTypeLocInfo {
diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td
index 8d2a362abc3c32..0c98f8e25a6fbb 100644
--- a/clang/include/clang/Basic/Attr.td
+++ b/clang/include/clang/Basic/Attr.td
@@ -4643,16 +4643,14 @@ def HLSLResource : InheritableAttr {
   let Documentation = [InternalOnly];
 }
 
-def HLSLROV : InheritableAttr {
+def HLSLROV : TypeAttr {
   let Spellings = [CXX11<"hlsl", "is_rov">];
-  let Subjects = SubjectList<[Struct]>;
   let LangOpts = [HLSL]; 
   let Documentation = [InternalOnly];
 }
 
-def HLSLResourceClass : InheritableAttr {
+def HLSLResourceClass : TypeAttr {
   let Spellings = [CXX11<"hlsl", "resource_class">];
-  let Subjects = SubjectList<[Field]>;
   let LangOpts = [HLSL];
   let Args = [
 	EnumArgument<"ResourceClass", "llvm::hlsl::ResourceClass",
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index dcb49d8a67604a..4f522f68f080aa 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -12364,6 +12364,7 @@ def err_hlsl_packoffset_cross_reg_boundary : Error<"packoffset cannot cross regi
 def err_hlsl_packoffset_alignment_mismatch : Error<"packoffset at 'y' not match alignment %0 required by %1">;
 def err_hlsl_pointers_unsupported : Error<
   "%select{pointers|references}0 are unsupported in HLSL">;
+def err_missing_resource_class : Error<"HLSL resource needs to have [[hlsl::resource_class()]] attribute">;
 
 def err_hlsl_operator_unsupported : Error<
   "the '%select{&|*|->}0' operator is unsupported in HLSL">;
diff --git a/clang/include/clang/Sema/SemaHLSL.h b/clang/include/clang/Sema/SemaHLSL.h
index d79ca9a4fa18d1..5131458863e20b 100644
--- a/clang/include/clang/Sema/SemaHLSL.h
+++ b/clang/include/clang/Sema/SemaHLSL.h
@@ -15,8 +15,11 @@
 
 #include "clang/AST/ASTFwd.h"
 #include "clang/AST/Attr.h"
+#include "clang/AST/Type.h"
+#include "clang/AST/TypeLoc.h"
 #include "clang/Basic/SourceLocation.h"
 #include "clang/Sema/SemaBase.h"
+#include "llvm/ADT/SmallVector.h"
 #include "llvm/TargetParser/Triple.h"
 #include <initializer_list>
 
@@ -59,8 +62,6 @@ class SemaHLSL : public SemaBase {
   void handleSV_DispatchThreadIDAttr(Decl *D, const ParsedAttr &AL);
   void handlePackOffsetAttr(Decl *D, const ParsedAttr &AL);
   void handleShaderAttr(Decl *D, const ParsedAttr &AL);
-  void handleROVAttr(Decl *D, const ParsedAttr &AL);
-  void handleResourceClassAttr(Decl *D, const ParsedAttr &AL);
   void handleResourceBindingAttr(Decl *D, const ParsedAttr &AL);
   void handleParamModifierAttr(Decl *D, const ParsedAttr &AL);
   bool handleResourceTypeAttr(const ParsedAttr &AL);
@@ -77,6 +78,22 @@ class SemaHLSL : public SemaBase {
   ExprResult ActOnOutParamExpr(ParmVarDecl *Param, Expr *Arg);
 
   QualType getInoutParameterType(QualType Ty);
+
+  // FIXME: This can be hidden (as static function in SemaHLSL.cpp) once we no
+  // longer need to create builtin buffer types in HLSLExternalSemaSource.
+  static bool
+  CreateHLSLAttributedResourceType(Sema &S, QualType Wrapped,
+                                   llvm::SmallVector<const Attr *> &AttrList,
+                                   QualType &ResType);
+
+private:
+  // HLSL resource type attributes need to be processed all at once.
+  // This is a list to collect them.
+  llvm::SmallVector<const Attr*> HLSLResourcesTypeAttrs;
+
+  /// SourceRanges corresponding to HLSLAttributedResourceTypeLocs that we have not yet populated.
+  llvm::DenseMap<const HLSLAttributedResourceType *, SourceLocation>
+      LocsForHLSLAttributedResources;
 };
 
 } // namespace clang
diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp
index b1d9516c96eb7a..27b251a5575855 100644
--- a/clang/lib/AST/TypePrinter.cpp
+++ b/clang/lib/AST/TypePrinter.cpp
@@ -1942,6 +1942,10 @@ void TypePrinter::printAttributedAfter(const AttributedType *T,
   case attr::BTFTypeTag:
     llvm_unreachable("BTFTypeTag attribute handled separately");
 
+  case attr::HLSLResourceClass:
+  case attr::HLSLROV:
+    llvm_unreachable("HLSL resource type attributes handled separately");
+
   case attr::OpenCLPrivateAddressSpace:
   case attr::OpenCLGlobalAddressSpace:
   case attr::OpenCLGlobalDeviceAddressSpace:
@@ -2062,6 +2066,7 @@ void TypePrinter::printBTFTagAttributedAfter(const BTFTagAttributedType *T,
 void TypePrinter::printHLSLAttributedResourceBefore(
     const HLSLAttributedResourceType *T, raw_ostream &OS) {
   printBefore(T->getWrappedType(), OS);
+  printAfter(T->getWrappedType(), OS);
 
   const HLSLAttributedResourceType::Attributes &Attrs = T->getAttrs();
   OS << " [[hlsl::resource_class("
@@ -2072,9 +2077,7 @@ void TypePrinter::printHLSLAttributedResourceBefore(
 }
 
 void TypePrinter::printHLSLAttributedResourceAfter(
-    const HLSLAttributedResourceType *T, raw_ostream &OS) {
-  printAfter(T->getWrappedType(), OS);
-}
+    const HLSLAttributedResourceType *T, raw_ostream &OS) {}
 
 void TypePrinter::printObjCInterfaceBefore(const ObjCInterfaceType *T,
                                            raw_ostream &OS) {
diff --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp b/clang/lib/CodeGen/CGHLSLRuntime.cpp
index 4bd7b6ba58de0d..0abca7b000d177 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.cpp
+++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp
@@ -17,6 +17,7 @@
 #include "CodeGenModule.h"
 #include "TargetInfo.h"
 #include "clang/AST/Decl.h"
+#include "clang/AST/Type.h"
 #include "clang/Basic/TargetOptions.h"
 #include "llvm/IR/Metadata.h"
 #include "llvm/IR/Module.h"
@@ -295,13 +296,14 @@ void CGHLSLRuntime::annotateHLSLResource(const VarDecl *D, GlobalVariable *GV) {
   // inside the record decl
   for (auto *FD : RD->fields()) {
     const auto *HLSLResAttr = FD->getAttr<HLSLResourceAttr>();
-    const auto *HLSLResClassAttr = FD->getAttr<HLSLResourceClassAttr>();
-    if (!HLSLResAttr || !HLSLResClassAttr)
+    const HLSLAttributedResourceType *AttrResType =
+        dyn_cast<HLSLAttributedResourceType>(FD->getType().getTypePtr());
+    if (!HLSLResAttr || !AttrResType)
       continue;
 
-    llvm::hlsl::ResourceClass RC = HLSLResClassAttr->getResourceClass();
+    llvm::hlsl::ResourceClass RC = AttrResType->getAttrs().ResourceClass;
+    bool IsROV = AttrResType->getAttrs().IsROV;
     llvm::hlsl::ResourceKind RK = HLSLResAttr->getResourceKind();
-    bool IsROV = FD->hasAttr<HLSLROVAttr>();
     llvm::hlsl::ElementType ET = calculateElementType(CGM.getContext(), Ty);
 
     BufferResBinding Binding(D->getAttr<HLSLResourceBindingAttr>());
diff --git a/clang/lib/Sema/HLSLExternalSemaSource.cpp b/clang/lib/Sema/HLSLExternalSemaSource.cpp
index 9aacbe4ad9548e..07164069336dbd 100644
--- a/clang/lib/Sema/HLSLExternalSemaSource.cpp
+++ b/clang/lib/Sema/HLSLExternalSemaSource.cpp
@@ -13,10 +13,13 @@
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/Attr.h"
 #include "clang/AST/DeclCXX.h"
+#include "clang/AST/Type.h"
 #include "clang/Basic/AttrKinds.h"
 #include "clang/Basic/HLSLRuntime.h"
 #include "clang/Sema/Lookup.h"
 #include "clang/Sema/Sema.h"
+#include "clang/Sema/SemaHLSL.h"
+#include "llvm/ADT/SmallVector.h"
 #include "llvm/Frontend/HLSL/HLSLResource.h"
 
 #include <functional>
@@ -107,7 +110,7 @@ struct BuiltinTypeDeclBuilder {
   }
 
   BuiltinTypeDeclBuilder &
-  addHandleMember(ResourceClass RC, ResourceKind RK, bool IsROV,
+  addHandleMember(Sema &S, ResourceClass RC, ResourceKind RK, bool IsROV,
                   AccessSpecifier Access = AccessSpecifier::AS_private) {
     if (Record->isCompleteDefinition())
       return *this;
@@ -118,16 +121,18 @@ struct BuiltinTypeDeclBuilder {
         Ty = Record->getASTContext().getPointerType(
             QualType(TTD->getTypeForDecl(), 0));
     }
-    // add handle member
-    Attr *ResourceClassAttr =
-        HLSLResourceClassAttr::CreateImplicit(Record->getASTContext(), RC);
+
+    // add handle member with resource type attributes
+    QualType AttributedResTy = QualType();
+    SmallVector<const Attr*> Attrs = {
+      HLSLResourceClassAttr::CreateImplicit(Record->getASTContext(), RC),
+      IsROV ? HLSLROVAttr::CreateImplicit(Record->getASTContext()) : nullptr
+    };
     Attr *ResourceAttr =
         HLSLResourceAttr::CreateImplicit(Record->getASTContext(), RK);
-    Attr *ROVAttr =
-        IsROV ? HLSLROVAttr::CreateImplicit(Record->getASTContext()) : nullptr;
-    addMemberVariable("h", Ty, {ResourceClassAttr, ResourceAttr, ROVAttr},
-                      Access);
-
+    if (SemaHLSL::CreateHLSLAttributedResourceType(S, Ty, Attrs, AttributedResTy)) {
+      addMemberVariable("h", AttributedResTy, {ResourceAttr}, Access);
+    }
     return *this;
   }
 
@@ -494,7 +499,7 @@ static BuiltinTypeDeclBuilder setupBufferType(CXXRecordDecl *Decl, Sema &S,
                                               ResourceClass RC, ResourceKind RK,
                                               bool IsROV) {
   return BuiltinTypeDeclBuilder(Decl)
-      .addHandleMember(RC, RK, IsROV)
+      .addHandleMember(S, RC, RK, IsROV)
       .addDefaultHandleConstructor(S, RC);
 }
 
diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index 33547c2e6e1452..d068cb6a78f266 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -6907,12 +6907,6 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL,
   case ParsedAttr::AT_HLSLResourceBinding:
     S.HLSL().handleResourceBindingAttr(D, AL);
     break;
-  case ParsedAttr::AT_HLSLROV:
-    handleSimpleAttribute<HLSLROVAttr>(S, D, AL);
-    break;
-  case ParsedAttr::AT_HLSLResourceClass:
-    S.HLSL().handleResourceClassAttr(D, AL);
-    break;
   case ParsedAttr::AT_HLSLParamModifier:
     S.HLSL().handleParamModifierAttr(D, AL);
     break;
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index 778d524a005482..69f4382e465300 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -9,9 +9,12 @@
 //===----------------------------------------------------------------------===//
 
 #include "clang/Sema/SemaHLSL.h"
+#include "clang/AST/ASTContext.h"
 #include "clang/AST/Decl.h"
 #include "clang/AST/Expr.h"
 #include "clang/AST/RecursiveASTVisitor.h"
+#include "clang/AST/Type.h"
+#include "clang/Basic/AttrKinds.h"
 #include "clang/Basic/DiagnosticSema.h"
 #include "clang/Basic/LLVM.h"
 #include "clang/Basic/SourceLocation.h"
@@ -19,7 +22,9 @@
 #include "clang/Sema/Initialization.h"
 #include "clang/Sema/ParsedAttr.h"
 #include "clang/Sema/Sema.h"
+#include "clang/Sema/Template.h"
 #include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/Support/Casting.h"
@@ -27,6 +32,7 @@
 #include "llvm/Support/ErrorHandling.h"
 #include "llvm/TargetParser/Triple.h"
 #include <iterator>
+#include <utility>
 
 using namespace clang;
 
@@ -556,46 +562,113 @@ void SemaHLSL::handleShaderAttr(Decl *D, const ParsedAttr &AL) {
     D->addAttr(NewAttr);
 }
 
-void SemaHLSL::handleResourceClassAttr(Decl *D, const ParsedAttr &AL) {
-  if (!AL.isArgIdent(0)) {
-    Diag(AL.getLoc(), diag::err_attribute_argument_type)
-        << AL << AANT_ArgumentIdentifier;
-    return;
-  }
+bool SemaHLSL::CreateHLSLAttributedResourceType(Sema &S, QualType Wrapped, llvm::SmallVector<const Attr *> &AttrList, QualType &ResType) {
+  assert(AttrList.size() && "expected list of resource attributes");
 
-  IdentifierLoc *Loc = AL.getArgAsIdent(0);
-  StringRef Identifier = Loc->Ident->getName();
-  SourceLocation ArgLoc = Loc->Loc;
+  QualType Contained = QualType();
+  HLSLAttributedResourceType::Attributes ResAttrs = {};
 
-  // Validate.
-  llvm::dxil::ResourceClass RC;
-  if (!HLSLResourceClassAttr::ConvertStrToResourceClass(Identifier, RC)) {
-    Diag(ArgLoc, diag::warn_attribute_type_not_supported)
-        << "ResourceClass" << Identifier;
-    return;
+  bool hasResourceClass = false;
+  for (auto *Attr : AttrList) {
+    if (!Attr)
+      continue;
+    switch (Attr->getKind()) {
+    case attr::HLSLResourceClass: {
+      llvm::dxil::ResourceClass RC = dyn_cast<HLSLResourceClassAttr>(Attr)->getResourceClass();
+      if (!hasResourceClass) {
+        ResAttrs.ResourceClass = RC;
+        hasResourceClass = true;
+      } else if (RC != ResAttrs.ResourceClass) {
+        S.Diag(Attr->getLocation(), diag::warn_duplicate_attribute) << Attr;
+        return false;
+      }
+      break;
+    }
+    case attr::HLSLROV:
+      ResAttrs.IsROV = true;
+      break;
+    default:
+      llvm_unreachable("unhandled resource attribute type");
+    }
+  }
+
+  if (!hasResourceClass) {
+    S.Diag(AttrList.back()->getRange().getEnd(), diag::err_missing_resource_class);
+    return false;
   }
 
-  D->addAttr(HLSLResourceClassAttr::Create(getASTContext(), RC, ArgLoc));
+  ResType = S.getASTContext().getHLSLAttributedResourceType(Wrapped, Contained, ResAttrs);
+  return true;
 }
 
-// Validates HLSL resource type attribute and adds it to the list to be
-// processed into a single HLSLAttributedResourceType later on.
-// Returns false if the attribute is invalid.
+// Validates and creates an HLSL attribute that is applied as type attribute on
+// HLSL resource. The attributes are collected in HLSLResourcesAttrs and at the
+// end of the declaration they are applied to the declaration type by wrapping
+// it in HLSLAttributedResourceType.
 bool SemaHLSL::handleResourceTypeAttr(const ParsedAttr &AL) {
-  // FIXME: placeholder - not yet implemented
+  Attr *A = nullptr;
+
+  // validate number of arguments
+  if (!AL.checkExactlyNumArgs(SemaRef, AL.getMinArgs()))
+    return false;
+
+  switch (AL.getKind()) {
+  case ParsedAttr::AT_HLSLResourceClass: {
+    if (!AL.isArgIdent(0)) {
+      Diag(AL.getLoc(), diag::err_attribute_argument_type)
+          << AL << AANT_ArgumentIdentifier;
+      return false;
+    }
+
+    IdentifierLoc *Loc = AL.getArgAsIdent(0);
+    StringRef Identifier = Loc->Ident->getName();
+    SourceLocation ArgLoc = Loc->Loc;
+
+    // Validate resource class value
+    llvm::dxil::ResourceClass RC;
+    if (!HLSLResourceClassAttr::ConvertStrToResourceClass(Identifier, RC)) {
+      Diag(ArgLoc, diag::warn_attribute_type_not_supported)
+          << "ResourceClass" << Identifier;
+      return false;
+    }
+    A = HLSLResourceClassAttr::Create(getASTContext(), RC, AL.getLoc());
+    break;
+  }
+  case ParsedAttr::AT_HLSLROV:
+    A = HLSLROVAttr::Create(getASTContext(), AL.getLoc());
+    break;
+  default:
+    llvm_unreachable("unhandled HLSL attribute");
+  }
+
+  HLSLResourcesTypeAttrs.emplace_back(A);
   return true;
 }
 
-// Combines all resource type attributes and create HLSLAttributedResourceType.
+// Combines all resource type attributes and creates HLSLAttributedResourceType.
 QualType SemaHLSL::ProcessResourceTypeAttributes(QualType CurrentType) {
-  // FIXME: placeholder - not yet implemented
-  return CurrentType;
+  if (!HLSLResourcesTypeAttrs.size())
+    return CurrentType;
+
+  QualType QT = CurrentType;
+  if (CreateHLSLAttributedResourceType(SemaRef, CurrentType, HLSLResourcesTypeAttrs, QT)) {
+    const HLSLAttributedResourceType *RT = dyn_cast<HLSLAttributedResourceType>(QT.getTypePtr());
+    SourceLocation Loc = HLSLResourcesTypeAttrs[0]->getLoc();
+    LocsForHLSLAttributedResources.insert(std::pair(RT, Loc));
+  }
+  HLSLResourcesTypeAttrs.clear();
+  return QT;
 }
 
 // Returns source location for the HLSLAttributedResourceType
 SourceLocation
 SemaHLSL::TakeLocForHLSLAttribute(const HLSLAttributedResourceType *RT) {
-  // FIXME: placeholder - not yet implemented
+  auto I = LocsForHLSLAttributedResources.find(RT);
+  if (I != LocsForHLSLAttributedResources.end()) {
+    SourceLocation Loc = I->second;
+    LocsForHLSLAttributedResources.erase(RT);
+    return Loc;
+  }
   return SourceLocation();
 }
 
@@ -653,33 +726,18 @@ static void updateResourceClassFlagsFromDeclResourceClass(
   }
 }
 
-template <typename T>
-static const T *getSpecifiedHLSLAttrFromRecordDecl(RecordDecl *TheRecordDecl) {
-  if (!TheRecordDecl)
-    return nullptr;
-
-  if (TheRecordDecl->hasAttr<T>())
-    return TheRecordDecl->getAttr<T>();
-  for (auto *FD : TheRecordDecl->fields()) {
-    const T *Attr = FD->getAttr<T>();
-    if (Attr)
-      return Attr;
+const HLSLAttributedResourceType *findAttributedResourceTypeOnField(VarDecl *VD) {
+  assert(VD != nullptr && "expected VarDecl");
+  if (RecordDecl *RD = getRecordDeclFromVarDecl(VD)) {
+    for (auto *FD : RD->fields()) {
+      if (const HLSLAttributedResourceType *AttrResType =
+              dyn_cast<HLSLAttributedResourceType>(FD->getType().getTypePtr()))
+        return AttrResType;
+    }
   }
   return nullptr;
 }
 
-template <typename T>
-static const T *getSpecifiedHLSLAttrFromVarDecl(VarDecl *VD) {
-  RecordDecl *TheRecordDecl = nullptr;
-  if (VD) {
-    TheRecordDecl = getRecordDeclFromVarDecl(VD);
-    if (!TheRecordDecl)
-      return nullptr;
-  }
-
-  return getSpecifiedHLSLAttrFromRecordDecl<T>(TheRecordDecl);
-}
-
 static void updateResourceClassFlagsFromRecordType(RegisterBindingFlags &Flags,
                                                    const RecordType *RT) {
   llvm::SmallVector<const Type *> TypesToScan;
@@ -699,10 +757,10 @@ static void updateResourceClassFlagsFromRecordType(RegisterBindingFlags &Flags,
 
     const RecordDecl *RD = RT->getDecl();
     for (FieldDecl *FD : RD->fields()) {
-      if (HLSLResourceClassAttr *RCAttr =
-              FD->getAttr<HLSLResourceClassAttr>()) {
-        updateResourceClassFlagsFromDeclResourceClass(
-            Flags, RCAttr->getResourceClass());
+      const Type *FieldTy = FD->getType().getTypePtr();
+      if (const HLSLAttributedResourceType *AttrResType =
+              dyn_cast<HLSLAttributedResourceType>(FieldTy)) {
+        updateResourceClassFlagsFromDeclResourceClass(Flags, AttrResType->getAttrs().ResourceClass);
         continue;
       }
       TypesToScan.emplace_back(FD->getType().getTypePtr());
@@ -729,11 +787,10 @@ static RegisterBindingFlags HLSLFillRegisterBindingFlags(Sema &S,
   }
   // Samplers, UAVs, and SRVs are VarDecl types
   else if (VarDecl *TheVarDecl = dyn_cast<VarDecl>(TheDecl)) {
-    const HLSLResourceClassAttr *resClassAttr =
-        getSpecifiedHLSLAttrFromVarDecl<HLSLResourceClassAttr>(TheVarDecl);
-    if (resClassAttr) {
+    if (const HLSLAttributedResourceType *AttrResType =
+            findAttributedResourceTypeOnField(TheVarDecl)) {
       Flags.Resource = true;
-      Flags.ResourceClass = resClassAttr->getResourceClass();
+      Flags.ResourceClass = AttrResType->getAttrs().ResourceClass;
     } else {
       const clang::Type *TheBaseType = TheVarDecl->getType().getTypePtr();
       while (TheBaseType->isArrayType())
@@ -758,7 +815,15 @@ static RegisterBindingFlags HLSLFillRegisterBindingFlags(Sema &S,
   return Flags;
 }
 
-enum class RegisterType { SRV, UAV, CBuffer, Sampler, C, I, Invalid };
+enum class RegisterType {
+  SRV = static_cast<int>(llvm::dxil::ResourceClass::SRV),
+  UAV = static_cast<int>(llvm::dxil::ResourceClass::UAV),
+  CBuffer = static_cast<int>(llvm::dxil::ResourceClass::CBuffer),
+  Sampler = static_cast<int>(llvm::dxil::ResourceClass::Sampler),
+  C,
+  I,
+  Invalid
+};
 
 static RegisterType getRegisterType(llvm::dxil::ResourceClass RC) {
   switch (RC) {
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 66e3f27fed9de0..06d3936b05b913 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -7462,8 +7462,26 @@ QualType TreeTransform<Derived>::TransformBTFTagAttributedType(
 template <typename Derived>
 QualType TreeTransform<Derived>::TransformHLSLAttributedResourceType(
     TypeLocBuilder &TLB, HLSLAttributedResourceTypeLoc TL) {
-  llvm_unreachable(
-      "Unexpected TreeTransform for HLSLAttributedResourceTypeLoc");
+
+  const HLSLAttributedResourceType *oldType = TL.getTypePtr();
+
+  QualType WrappedTy = getDerived().TransformType(TLB, TL.getWrappedLoc());
+  if (WrappedTy.isNull())
+    return QualType();
+
+  QualType ContainedTy = QualType();
+  if (!oldType->getContainedType().isNull())
+    ContainedTy = getDerived().TransformType(TLB, TL.getContainedLoc());
+
+  QualType Result = TL.getType();
+  if (getDerived().AlwaysRebuild() || WrappedTy != oldType->getWrappedType() ||
+      ContainedTy != oldType->getContainedType()) {
+    Result = SemaRef.Context.getHLSLAttributedResourceType(
+        WrappedTy, ContainedTy, oldType->getAttrs());
+  }
+
+  TLB.push<HLSLAttributedResourceTypeLoc>(Result);
+  return Result;
 }
 
 template<typename Derived>
diff --git a/clang/test/AST/HLSL/RWBuffer-AST.hlsl b/clang/test/AST/HLSL/RWBuffer-AST.hlsl
index 1f6ef60e121ea5..0e7803ce50a890 100644
--- a/clang/test/AST/HLSL/RWBuffer-AST.hlsl
+++ b/clang/test/AST/HLSL/RWBuffer-AST.hlsl
@@ -30,8 +30,7 @@ RWBuffer<float> Buffer;
 // CHECK-NEXT: CXXRecordDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> implicit class RWBuffer definition
 
 // CHECK: FinalAttr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> Implicit final
-// CHECK-NEXT: FieldDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> implicit h 'element_type *'
-// CHECK-NEXT: HLSLResourceClassAttr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> Implicit UAV
+// CHECK-NEXT: implicit h 'element_type * {{\[\[}}hlsl::resource_class(UAV)]]':'element_type *'
 // CHECK-NEXT: HLSLResourceAttr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> Implicit TypedBuffer
 
 // CHECK: CXXMethodDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> operator[] 'element_type &const (unsigned int) const'
@@ -39,7 +38,7 @@ RWBuffer<float> Buffer;
 // CHECK-NEXT: CompoundStmt 0x{{[0-9A-Fa-f]+}} <<invalid sloc>>
 // CHECK-NEXT: ReturnStmt 0x{{[0-9A-Fa-f]+}} <<invalid sloc>>
 // CHECK-NEXT: ArraySubscriptExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'element_type' lvalue
-// CHECK-NEXT: MemberExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'element_type *' lvalue .h 0x{{[0-9A-Fa-f]+}}
+// CHECK-NEXT: MemberExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'element_type * {{\[\[}}hlsl::resource_class(UAV)]]':'element_type *' lvalue .h 0x{{[0-9A-Fa-f]+}}
 // CHECK-NEXT: CXXThisExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'const RWBuffer<element_type>' lvalue implicit this
 // CHECK-NEXT: DeclRefExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'unsigned int' ParmVar 0x{{[0-9A-Fa-f]+}} 'Idx' 'unsigned int'
 // CHECK-NEXT: AlwaysInlineAttr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> Implicit always_inline
@@ -49,7 +48,7 @@ RWBuffer<float> Buffer;
 // CHECK-NEXT: CompoundStmt 0x{{[0-9A-Fa-f]+}} <<invalid sloc>>
 // CHECK-NEXT: ReturnStmt 0x{{[0-9A-Fa-f]+}} <<invalid sloc>>
 // CHECK-NEXT: ArraySubscriptExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'element_type' lvalue
-// CHECK-NEXT: MemberExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'element_type *' lvalue .h 0x{{[0-9A-Fa-f]+}}
+// CHECK-NEXT: MemberExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'element_type * {{\[\[}}hlsl::resource_class(UAV)]]':'element_type *' lvalue .h 0x{{[0-9A-Fa-f]+}}
 // CHECK-NEXT: CXXThisExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'RWBuffer<element_type>' lvalue implicit this
 // CHECK-NEXT: DeclRefExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'unsigned int' ParmVar 0x{{[0-9A-Fa-f]+}} 'Idx' 'unsigned int'
 // CHECK-NEXT: AlwaysInlineAttr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> Implicit always_inline
@@ -59,6 +58,5 @@ RWBuffer<float> Buffer;
 // CHECK: TemplateArgument type 'float'
 // CHECK-NEXT: BuiltinType 0x{{[0-9A-Fa-f]+}} 'float'
 // CHECK-NEXT: FinalAttr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> Implicit final
-// CHECK-NEXT: FieldDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> implicit referenced h 'float *'
-// CHECK-NEXT: HLSLResourceClassAttr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> Implicit UAV
+// CHECK-NEXT: FieldDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> implicit referenced h 'float * {{\[\[}}hlsl::resource_class(UAV)]]':'float *'
 // CHECK-NEXT: HLSLResourceAttr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> Implicit TypedBuffer
diff --git a/clang/test/Misc/pragma-attribute-supported-attributes-list.test b/clang/test/Misc/pragma-attribute-supported-attributes-list.test
index 5ebbd29b316bfa..eca86331149028 100644
--- a/clang/test/Misc/pragma-attribute-supported-attributes-list.test
+++ b/clang/test/Misc/pragma-attribute-supported-attributes-list.test
@@ -82,8 +82,6 @@
 // CHECK-NEXT: FunctionReturnThunks (SubjectMatchRule_function)
 // CHECK-NEXT: GNUInline (SubjectMatchRule_function)
 // CHECK-NEXT: HIPManaged (SubjectMatchRule_variable)
-// CHECK-NEXT: HLSLROV (SubjectMatchRule_record_not_is_union)
-// CHECK-NEXT: HLSLResourceClass (SubjectMatchRule_field)
 // CHECK-NEXT: Hot (SubjectMatchRule_function)
 // CHECK-NEXT: HybridPatchable (SubjectMatchRule_function)
 // CHECK-NEXT: IBAction (SubjectMatchRule_objc_method_is_instance)
diff --git a/clang/test/ParserHLSL/hlsl_is_rov_attr.hlsl b/clang/test/ParserHLSL/hlsl_is_rov_attr.hlsl
index 29850828ad3bc2..24c85c6ccf7d74 100644
--- a/clang/test/ParserHLSL/hlsl_is_rov_attr.hlsl
+++ b/clang/test/ParserHLSL/hlsl_is_rov_attr.hlsl
@@ -1,9 +1,16 @@
 // RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-compute -x hlsl -ast-dump -o - %s | FileCheck %s
 
-
-// CHECK: -HLSLROVAttr 0x{{[0-9a-f]+}} <col:10, col:16>
-struct [[hlsl::is_rov]] Eg1 {
-  int i;  
+// CHECK: CXXRecordDecl 0x{{[0-9a-f]+}} {{.*}} struct MyBuffer definition
+// CHECK: FieldDecl 0x{{[0-9a-f]+}} <line:6:3, col:68> col:68 h '__hlsl_resource_t {{\[\[}}hlsl::resource_class(UAV)]] {{\[\[}}hlsl::is_rov()]]':'__hlsl_resource_t'
+struct MyBuffer {
+  __hlsl_resource_t [[hlsl::resource_class(UAV)]] [[hlsl::is_rov]] h;
 };
 
-Eg1 e1;
+// CHECK: VarDecl 0x{{[0-9a-f]+}} <line:10:1, col:66> col:66 res '__hlsl_resource_t {{\[\[}}hlsl::resource_class(SRV)]] {{\[\[}}hlsl::is_rov()]]':'__hlsl_resource_t'
+__hlsl_resource_t [[hlsl::is_rov]] [[hlsl::resource_class(SRV)]] res;
+
+// CHECK: FunctionDecl 0x{{[0-9a-f]+}} <line:14:1, line:16:1> line:14:6 f 'void ()
+// CHECK: VarDecl 0x{{[0-9a-f]+}} <col:3, col:72> col:72 r '__hlsl_resource_t {{\[\[}}hlsl::resource_class(Sampler)]] {{\[\[}}hlsl::is_rov()]]':'__hlsl_resource_t'
+void f() {
+  __hlsl_resource_t [[hlsl::resource_class(Sampler)]] [[hlsl::is_rov]] r;
+}
diff --git a/clang/test/ParserHLSL/hlsl_is_rov_attr_error.hlsl b/clang/test/ParserHLSL/hlsl_is_rov_attr_error.hlsl
index a21fed22220b6d..68b2d9ecb190a8 100644
--- a/clang/test/ParserHLSL/hlsl_is_rov_attr_error.hlsl
+++ b/clang/test/ParserHLSL/hlsl_is_rov_attr_error.hlsl
@@ -1,15 +1,16 @@
-// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-compute -x hlsl -ast-dump -o - %s -verify
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-compute -x hlsl -o - %s -verify
 
-// expected-error at +1{{'is_rov' attribute takes no arguments}}
-struct [[hlsl::is_rov(3)]] Eg1 {
-  int i;  
-};
+// expected-error at +1{{'is_rov' attribute cannot be applied to a declaration}}
+[[hlsl::is_rov()]] __hlsl_resource_t res0;
 
-Eg1 e1;
+// expected-error at +1{{HLSL resource needs to have [[hlsl::resource_class()]] attribute}}
+__hlsl_resource_t [[hlsl::is_rov()]] res1;
 
+// expected-error at +1{{'is_rov' attribute takes no arguments}}
+__hlsl_resource_t [[hlsl::resource_class(UAV)]] [[hlsl::is_rov(3)]] res2;
+  
 // expected-error at +1{{use of undeclared identifier 'gibberish'}}
-struct [[hlsl::is_rov(gibberish)]] Eg2 {
-  int i;  
-};
+__hlsl_resource_t [[hlsl::resource_class(UAV)]] [[hlsl::is_rov(gibberish)]] res3;
 
-Eg2 e2;
+// duplicate attribute with the same meaning - no error
+__hlsl_resource_t [[hlsl::resource_class(UAV)]] [[hlsl::is_rov()]] [[hlsl::is_rov()]] res4;
diff --git a/clang/test/ParserHLSL/hlsl_resource_class_attr.hlsl b/clang/test/ParserHLSL/hlsl_resource_class_attr.hlsl
index 4b002e2d890093..2e25e58d4253e8 100644
--- a/clang/test/ParserHLSL/hlsl_resource_class_attr.hlsl
+++ b/clang/test/ParserHLSL/hlsl_resource_class_attr.hlsl
@@ -1,32 +1,32 @@
 // RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-compute -x hlsl -ast-dump -o - %s | FileCheck %s
 
-
-// CHECK: -HLSLResourceClassAttr 0x{{[0-9a-f]+}} <col:26> SRV
-struct Eg1 {
-  [[hlsl::resource_class(SRV)]] int i;  
+// CHECK: CXXRecordDecl 0x{{[0-9a-f]+}} {{.*}} struct MyBuffer definition
+// CHECK: FieldDecl 0x{{[0-9a-f]+}} <line:6:3, col:51> col:51 h '__hlsl_resource_t {{\[\[}}hlsl::resource_class(UAV)]]':'__hlsl_resource_t'
+struct MyBuffer {
+  __hlsl_resource_t [[hlsl::resource_class(UAV)]] h;
 };
 
-Eg1 e1;
-
-// CHECK: -CXXRecordDecl 0x{{[0-9a-f]+}} <line:13:1, line:15:1> line:13:8 referenced struct Eg2 definition
-// CHECK: -HLSLResourceClassAttr 0x{{[0-9a-f]+}} <col:26> UAV
-struct Eg2 {
-  [[hlsl::resource_class(UAV)]] int i;
-};
-Eg2 e2;
+// CHECK: VarDecl 0x{{[0-9a-f]+}} <line:10:1, col:49> col:49 res '__hlsl_resource_t {{\[\[}}hlsl::resource_class(SRV)]]':'__hlsl_resource_t'
+__hlsl_resource_t [[hlsl::resource_class(SRV)]] res;
 
-// CHECK: -CXXRecordDecl 0x{{[0-9a-f]+}} <line:20:1, line:22:1> line:20:8 referenced struct Eg3 definition
-// CHECK: -HLSLResourceClassAttr 0x{{[0-9a-f]+}} <col:26> CBuffer
-struct Eg3 {
-  [[hlsl::resource_class(CBuffer)]] int i;
-}; 
-Eg3 e3;
+// CHECK: FunctionDecl 0x{{[0-9a-f]+}} <line:14:1, line:16:1> line:14:6 f 'void ()
+// CHECK: VarDecl 0x{{[0-9a-f]+}} <col:3, col:55> col:55 r '__hlsl_resource_t {{\[\[}}hlsl::resource_class(Sampler)]]':'__hlsl_resource_t'
+void f() {
+  __hlsl_resource_t [[hlsl::resource_class(Sampler)]] r;
+}
 
-// CHECK: -CXXRecordDecl 0x{{[0-9a-f]+}} <line:27:1, line:29:1> line:27:8 referenced struct Eg4 definition
-// CHECK: -HLSLResourceClassAttr 0x{{[0-9a-f]+}} <col:26> Sampler
-struct Eg4 {
-  [[hlsl::resource_class(Sampler)]] int i;
+// CHECK: ClassTemplateDecl 0x{{[0-9a-f]+}} <line:23:1, line:25:1> line:23:29 MyBuffer2
+// CHECK: TemplateTypeParmDecl 0x{{[0-9a-f]+}} <col:10, col:19> col:19 referenced typename depth 0 index 0 T
+// CHECK: CXXRecordDecl 0x{{[0-9a-f]+}} <col:22, line:25:1> line:23:29 struct MyBuffer2 definition
+// CHECK: CXXRecordDecl 0x{{[0-9a-f]+}} <col:22, col:29> col:29 implicit struct MyBuffer2
+// CHECK: FieldDecl 0x{{[0-9a-f]+}} <line:24:3, col:35> col:35 h 'T {{\[\[}}hlsl::resource_class(UAV)]]':'T'
+template<typename T> struct MyBuffer2 {
+  T [[hlsl::resource_class(UAV)]] h;
 };
-Eg4 e4;
 
-RWBuffer<int> In : register(u1);
+// CHECK: ClassTemplateSpecializationDecl 0x{{[0-9a-f]+}} <line:23:1, line:25:1> line:23:29 struct MyBuffer2 definition implicit_instantiation
+// CHECK: TemplateArgument type 'float'
+// CHECK: BuiltinType 0x{{[0-9a-f]+}} 'float'
+// CHECK: CXXRecordDecl 0x{{[0-9a-f]+}} <col:22, col:29> col:29 implicit struct MyBuffer2
+// CHECK: FieldDecl 0x{{[0-9a-f]+}} <line:24:3, col:35> col:35 h 'float {{\[\[}}hlsl::resource_class(UAV)]]':'float'
+MyBuffer2<float> myBuffer2;
diff --git a/clang/test/ParserHLSL/hlsl_resource_class_attr_error.hlsl b/clang/test/ParserHLSL/hlsl_resource_class_attr_error.hlsl
index 76bed2f0607830..bb0e9e4621593f 100644
--- a/clang/test/ParserHLSL/hlsl_resource_class_attr_error.hlsl
+++ b/clang/test/ParserHLSL/hlsl_resource_class_attr_error.hlsl
@@ -1,22 +1,23 @@
-// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-compute -x hlsl -ast-dump -o - %s -verify
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-compute -x hlsl -o - %s -verify
 
-struct Eg1 {
-// expected-error at +1{{'resource_class' attribute takes one argument}}
-  [[hlsl::resource_class()]] int i;  
+struct SomeType {
+  int i;  
 };
 
-Eg1 e1;
+// expected-error at +1{{'resource_class' attribute cannot be applied to a declaration}}
+[[hlsl::resource_class(UAV)]] SomeType e0;
+
+// expected-error at +1{{'resource_class' attribute takes one argument}}
+SomeType [[hlsl::resource_class()]] e1;
 
-struct Eg2 {
 // expected-warning at +1{{ResourceClass attribute argument not supported: gibberish}}
-  [[hlsl::resource_class(gibberish)]] int i;  
-};
+SomeType [[hlsl::resource_class(gibberish)]] e2;
 
-Eg2 e2;
+// expected-warning at +1{{attribute 'resource_class' is already applied with different arguments}}
+SomeType [[hlsl::resource_class(SRV)]] [[hlsl::resource_class(UAV)]] e3;
 
-// expected-warning at +1{{'resource_class' attribute only applies to non-static data members}}
-struct [[hlsl::resource_class(SRV)]] Eg3 {
-  int i;  
-};
+// duplicate attribute with the same meaning - no error
+SomeType [[hlsl::resource_class(SRV)]] [[hlsl::resource_class(SRV)]] e4;
 
-Eg3 e3;
+// expected-error at +1{{'resource_class' attribute takes one argument}}
+SomeType [[hlsl::resource_class(SRV, "aa")]] e5;
diff --git a/clang/test/ParserHLSL/hlsl_resource_handle_attrs.hlsl b/clang/test/ParserHLSL/hlsl_resource_handle_attrs.hlsl
index 320d1160e761dd..6324a11fc8a2df 100644
--- a/clang/test/ParserHLSL/hlsl_resource_handle_attrs.hlsl
+++ b/clang/test/ParserHLSL/hlsl_resource_handle_attrs.hlsl
@@ -1,15 +1,16 @@
 // RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -x hlsl -ast-dump -o - %s | FileCheck %s
 
 // CHECK: -ClassTemplateSpecializationDecl 0x{{[0-9a-f]+}} <<invalid sloc>> <invalid sloc> class RWBuffer definition implicit_instantiation
-// CHECK: -FieldDecl 0x{{[0-9a-f]+}} <<invalid sloc>> <invalid sloc> implicit referenced h 'float *'
-// CHECK: -HLSLResourceClassAttr 0x{{[0-9a-f]+}} <<invalid sloc>> Implicit UAV
+// CHECK: -TemplateArgument type 'float'
+// CHECK: `-BuiltinType 0x{{[0-9a-f]+}} 'float'
+// CHECK: -FieldDecl 0x{{[0-9a-f]+}} <<invalid sloc>> <invalid sloc> implicit referenced h 'float * {{\[\[}}hlsl::resource_class(UAV)]]':'float *'
 // CHECK: -HLSLResourceAttr 0x{{[0-9a-f]+}} <<invalid sloc>> Implicit TypedBuffer
 RWBuffer<float> Buffer1;
 
-// CHECK: -ClassTemplateDecl 0x{{[0-9a-f]+}} <<invalid sloc>> <invalid sloc> implicit RasterizerOrderedBuffer
-// CHECK: -CXXRecordDecl 0x{{[0-9a-f]+}} <<invalid sloc>> <invalid sloc> implicit class RasterizerOrderedBuffer definition
-// CHECK: -FieldDecl 0x{{[0-9a-f]+}} <<invalid sloc>> <invalid sloc> implicit h 'element_type *'
-// CHECK: -HLSLResourceClassAttr 0x{{[0-9a-f]+}} <<invalid sloc>> Implicit UAV
+// CHECK: -ClassTemplateSpecializationDecl 0x{{[0-9a-f]+}} <<invalid sloc>> <invalid sloc> class RasterizerOrderedBuffer definition implicit_instantiation
+// CHECK: -TemplateArgument type 'vector<float, 4>'
+// CHECK: `-ExtVectorType 0x{{[0-9a-f]+}} 'vector<float, 4>' 4
+// CHECK: `-BuiltinType 0x{{[0-9a-f]+}} 'float'
+// CHECK: -FieldDecl 0x{{[0-9a-f]+}} <<invalid sloc>> <invalid sloc> implicit referenced h 'vector<float *, 4> {{\[\[}}hlsl::resource_class(UAV)]] {{\[\[}}hlsl::is_rov()]]':'vector<float *, 4>'
 // CHECK: -HLSLResourceAttr 0x{{[0-9a-f]+}} <<invalid sloc>> Implicit TypedBuffer
-// CHECK: -HLSLROVAttr 0x{{[0-9a-f]+}} <<invalid sloc>> Implicit
-RasterizerOrderedBuffer<vector<float, 4> > BufferArray3[4] : register(u4, space1);
+RasterizerOrderedBuffer<vector<float, 4> > BufferArray3[4];
diff --git a/clang/test/SemaHLSL/resource_binding_attr_error.hlsl b/clang/test/SemaHLSL/resource_binding_attr_error.hlsl
index 6a0b5956545dd8..9a0474730ed17d 100644
--- a/clang/test/SemaHLSL/resource_binding_attr_error.hlsl
+++ b/clang/test/SemaHLSL/resource_binding_attr_error.hlsl
@@ -2,7 +2,7 @@
 
 template<typename T>
 struct MyTemplatedSRV {
-  [[hlsl::resource_class(SRV)]] T x;
+  T [[hlsl::resource_class(SRV)]] x;
 };
 
 // valid, The register keyword in this statement isn't binding a resource, rather it is
diff --git a/clang/test/SemaHLSL/resource_binding_attr_error_resource.hlsl b/clang/test/SemaHLSL/resource_binding_attr_error_resource.hlsl
index c40d1d7f60b347..6e9df45da48057 100644
--- a/clang/test/SemaHLSL/resource_binding_attr_error_resource.hlsl
+++ b/clang/test/SemaHLSL/resource_binding_attr_error_resource.hlsl
@@ -6,23 +6,23 @@
 
 template<typename T>
 struct MyTemplatedSRV {
-  [[hlsl::resource_class(SRV)]] T x;
+  T [[hlsl::resource_class(SRV)]] x;
 };
 
 struct MySRV {
-  [[hlsl::resource_class(SRV)]] int x;
+  int [[hlsl::resource_class(SRV)]] x;
 };
 
 struct MySampler {
-  [[hlsl::resource_class(Sampler)]] int x;
+  int [[hlsl::resource_class(Sampler)]] x;
 };
 
 struct MyUAV {
-  [[hlsl::resource_class(UAV)]] int x;
+  int [[hlsl::resource_class(UAV)]] x;
 };
 
 struct MyCBuffer {
-  [[hlsl::resource_class(CBuffer)]] int x;
+  int [[hlsl::resource_class(CBuffer)]] x;
 };
 
 
diff --git a/clang/test/SemaHLSL/resource_binding_attr_error_udt.hlsl b/clang/test/SemaHLSL/resource_binding_attr_error_udt.hlsl
index edb3f30739cdfd..8bc20f72b0d0b3 100644
--- a/clang/test/SemaHLSL/resource_binding_attr_error_udt.hlsl
+++ b/clang/test/SemaHLSL/resource_binding_attr_error_udt.hlsl
@@ -2,23 +2,23 @@
 
 template<typename T>
 struct MyTemplatedUAV {
-  [[hlsl::resource_class(UAV)]] T x;
+  T [[hlsl::resource_class(UAV)]] x;
 };
 
 struct MySRV {
-  [[hlsl::resource_class(SRV)]] int x;
+  int [[hlsl::resource_class(SRV)]] x;
 };
 
 struct MySampler {
-  [[hlsl::resource_class(Sampler)]] int x;
+  int [[hlsl::resource_class(Sampler)]] x;
 };
 
 struct MyUAV {
-  [[hlsl::resource_class(UAV)]] int x;
+  int [[hlsl::resource_class(UAV)]] x;
 };
 
 struct MyCBuffer {
-  [[hlsl::resource_class(CBuffer)]] int x;
+  int [[hlsl::resource_class(CBuffer)]] x;
 };
 
 // Valid: f is skipped, SRVBuf is bound to t0, UAVBuf is bound to u0

>From ba9d46516a267c95d70a00745405248e192449e4 Mon Sep 17 00:00:00 2001
From: Helena Kotas <hekotas at microsoft.com>
Date: Tue, 3 Sep 2024 16:14:43 -0700
Subject: [PATCH 2/6] clang-format, cleanup

---
 clang/include/clang/Sema/SemaHLSL.h       |  6 ++--
 clang/lib/CodeGen/CGHLSLRuntime.cpp       |  1 -
 clang/lib/Sema/HLSLExternalSemaSource.cpp | 10 +++----
 clang/lib/Sema/SemaHLSL.cpp               | 35 ++++++++++++-----------
 4 files changed, 26 insertions(+), 26 deletions(-)

diff --git a/clang/include/clang/Sema/SemaHLSL.h b/clang/include/clang/Sema/SemaHLSL.h
index 5131458863e20b..f340ed367f8cf3 100644
--- a/clang/include/clang/Sema/SemaHLSL.h
+++ b/clang/include/clang/Sema/SemaHLSL.h
@@ -16,7 +16,6 @@
 #include "clang/AST/ASTFwd.h"
 #include "clang/AST/Attr.h"
 #include "clang/AST/Type.h"
-#include "clang/AST/TypeLoc.h"
 #include "clang/Basic/SourceLocation.h"
 #include "clang/Sema/SemaBase.h"
 #include "llvm/ADT/SmallVector.h"
@@ -89,9 +88,10 @@ class SemaHLSL : public SemaBase {
 private:
   // HLSL resource type attributes need to be processed all at once.
   // This is a list to collect them.
-  llvm::SmallVector<const Attr*> HLSLResourcesTypeAttrs;
+  llvm::SmallVector<const Attr *> HLSLResourcesTypeAttrs;
 
-  /// SourceRanges corresponding to HLSLAttributedResourceTypeLocs that we have not yet populated.
+  /// SourceLocation corresponding to HLSLAttributedResourceTypeLocs that we
+  /// have not yet populated.
   llvm::DenseMap<const HLSLAttributedResourceType *, SourceLocation>
       LocsForHLSLAttributedResources;
 };
diff --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp b/clang/lib/CodeGen/CGHLSLRuntime.cpp
index 0abca7b000d177..b6e6555e63fca1 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.cpp
+++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp
@@ -17,7 +17,6 @@
 #include "CodeGenModule.h"
 #include "TargetInfo.h"
 #include "clang/AST/Decl.h"
-#include "clang/AST/Type.h"
 #include "clang/Basic/TargetOptions.h"
 #include "llvm/IR/Metadata.h"
 #include "llvm/IR/Module.h"
diff --git a/clang/lib/Sema/HLSLExternalSemaSource.cpp b/clang/lib/Sema/HLSLExternalSemaSource.cpp
index 07164069336dbd..37d24eefb5e66c 100644
--- a/clang/lib/Sema/HLSLExternalSemaSource.cpp
+++ b/clang/lib/Sema/HLSLExternalSemaSource.cpp
@@ -124,13 +124,13 @@ struct BuiltinTypeDeclBuilder {
 
     // add handle member with resource type attributes
     QualType AttributedResTy = QualType();
-    SmallVector<const Attr*> Attrs = {
-      HLSLResourceClassAttr::CreateImplicit(Record->getASTContext(), RC),
-      IsROV ? HLSLROVAttr::CreateImplicit(Record->getASTContext()) : nullptr
-    };
+    SmallVector<const Attr *> Attrs = {
+        HLSLResourceClassAttr::CreateImplicit(Record->getASTContext(), RC),
+        IsROV ? HLSLROVAttr::CreateImplicit(Record->getASTContext()) : nullptr};
     Attr *ResourceAttr =
         HLSLResourceAttr::CreateImplicit(Record->getASTContext(), RK);
-    if (SemaHLSL::CreateHLSLAttributedResourceType(S, Ty, Attrs, AttributedResTy)) {
+    if (SemaHLSL::CreateHLSLAttributedResourceType(S, Ty, Attrs,
+                                                   AttributedResTy)) {
       addMemberVariable("h", AttributedResTy, {ResourceAttr}, Access);
     }
     return *this;
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index 69f4382e465300..b542465ee2b6e5 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -562,7 +562,9 @@ void SemaHLSL::handleShaderAttr(Decl *D, const ParsedAttr &AL) {
     D->addAttr(NewAttr);
 }
 
-bool SemaHLSL::CreateHLSLAttributedResourceType(Sema &S, QualType Wrapped, llvm::SmallVector<const Attr *> &AttrList, QualType &ResType) {
+bool SemaHLSL::CreateHLSLAttributedResourceType(
+    Sema &S, QualType Wrapped, llvm::SmallVector<const Attr *> &AttrList,
+    QualType &ResType) {
   assert(AttrList.size() && "expected list of resource attributes");
 
   QualType Contained = QualType();
@@ -574,7 +576,8 @@ bool SemaHLSL::CreateHLSLAttributedResourceType(Sema &S, QualType Wrapped, llvm:
       continue;
     switch (Attr->getKind()) {
     case attr::HLSLResourceClass: {
-      llvm::dxil::ResourceClass RC = dyn_cast<HLSLResourceClassAttr>(Attr)->getResourceClass();
+      llvm::dxil::ResourceClass RC =
+          dyn_cast<HLSLResourceClassAttr>(Attr)->getResourceClass();
       if (!hasResourceClass) {
         ResAttrs.ResourceClass = RC;
         hasResourceClass = true;
@@ -593,11 +596,13 @@ bool SemaHLSL::CreateHLSLAttributedResourceType(Sema &S, QualType Wrapped, llvm:
   }
 
   if (!hasResourceClass) {
-    S.Diag(AttrList.back()->getRange().getEnd(), diag::err_missing_resource_class);
+    S.Diag(AttrList.back()->getRange().getEnd(),
+           diag::err_missing_resource_class);
     return false;
   }
 
-  ResType = S.getASTContext().getHLSLAttributedResourceType(Wrapped, Contained, ResAttrs);
+  ResType = S.getASTContext().getHLSLAttributedResourceType(Wrapped, Contained,
+                                                            ResAttrs);
   return true;
 }
 
@@ -651,8 +656,10 @@ QualType SemaHLSL::ProcessResourceTypeAttributes(QualType CurrentType) {
     return CurrentType;
 
   QualType QT = CurrentType;
-  if (CreateHLSLAttributedResourceType(SemaRef, CurrentType, HLSLResourcesTypeAttrs, QT)) {
-    const HLSLAttributedResourceType *RT = dyn_cast<HLSLAttributedResourceType>(QT.getTypePtr());
+  if (CreateHLSLAttributedResourceType(SemaRef, CurrentType,
+                                       HLSLResourcesTypeAttrs, QT)) {
+    const HLSLAttributedResourceType *RT =
+        dyn_cast<HLSLAttributedResourceType>(QT.getTypePtr());
     SourceLocation Loc = HLSLResourcesTypeAttrs[0]->getLoc();
     LocsForHLSLAttributedResources.insert(std::pair(RT, Loc));
   }
@@ -726,7 +733,8 @@ static void updateResourceClassFlagsFromDeclResourceClass(
   }
 }
 
-const HLSLAttributedResourceType *findAttributedResourceTypeOnField(VarDecl *VD) {
+const HLSLAttributedResourceType *
+findAttributedResourceTypeOnField(VarDecl *VD) {
   assert(VD != nullptr && "expected VarDecl");
   if (RecordDecl *RD = getRecordDeclFromVarDecl(VD)) {
     for (auto *FD : RD->fields()) {
@@ -760,7 +768,8 @@ static void updateResourceClassFlagsFromRecordType(RegisterBindingFlags &Flags,
       const Type *FieldTy = FD->getType().getTypePtr();
       if (const HLSLAttributedResourceType *AttrResType =
               dyn_cast<HLSLAttributedResourceType>(FieldTy)) {
-        updateResourceClassFlagsFromDeclResourceClass(Flags, AttrResType->getAttrs().ResourceClass);
+        updateResourceClassFlagsFromDeclResourceClass(
+            Flags, AttrResType->getAttrs().ResourceClass);
         continue;
       }
       TypesToScan.emplace_back(FD->getType().getTypePtr());
@@ -815,15 +824,7 @@ static RegisterBindingFlags HLSLFillRegisterBindingFlags(Sema &S,
   return Flags;
 }
 
-enum class RegisterType {
-  SRV = static_cast<int>(llvm::dxil::ResourceClass::SRV),
-  UAV = static_cast<int>(llvm::dxil::ResourceClass::UAV),
-  CBuffer = static_cast<int>(llvm::dxil::ResourceClass::CBuffer),
-  Sampler = static_cast<int>(llvm::dxil::ResourceClass::Sampler),
-  C,
-  I,
-  Invalid
-};
+enum class RegisterType { SRV, UAV, CBuffer, Sampler, C, I, Invalid };
 
 static RegisterType getRegisterType(llvm::dxil::ResourceClass RC) {
   switch (RC) {

>From 4e99c5f07fb70fa68ef1f2239d67dd6e645866b5 Mon Sep 17 00:00:00 2001
From: Helena Kotas <hekotas at microsoft.com>
Date: Tue, 3 Sep 2024 16:45:18 -0700
Subject: [PATCH 3/6] Update comment

---
 clang/lib/Sema/SemaHLSL.cpp | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index b542465ee2b6e5..c2f52f49e10398 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -607,9 +607,9 @@ bool SemaHLSL::CreateHLSLAttributedResourceType(
 }
 
 // Validates and creates an HLSL attribute that is applied as type attribute on
-// HLSL resource. The attributes are collected in HLSLResourcesAttrs and at the
-// end of the declaration they are applied to the declaration type by wrapping
-// it in HLSLAttributedResourceType.
+// HLSL resource. The attributes are collected in HLSLResourcesTypeAttrs and at
+// the end of the declaration they are applied to the declaration type by
+// wrapping it in HLSLAttributedResourceType.
 bool SemaHLSL::handleResourceTypeAttr(const ParsedAttr &AL) {
   Attr *A = nullptr;
 

>From dfd0d0f23ed9df3e3cc8a54a39ba3a3a48e1808f Mon Sep 17 00:00:00 2001
From: Helena Kotas <hekotas at microsoft.com>
Date: Wed, 4 Sep 2024 12:18:02 -0700
Subject: [PATCH 4/6] Address code review feedback

- use __hlsl_resource_t in tests
- move function out of SemaHLSL
- call erase with iterator
---
 clang/include/clang/Sema/SemaHLSL.h              | 13 ++++++-------
 clang/lib/Sema/HLSLExternalSemaSource.cpp        |  4 +---
 clang/lib/Sema/SemaHLSL.cpp                      |  4 ++--
 .../ParserHLSL/hlsl_resource_class_attr.hlsl     |  8 ++++----
 .../hlsl_resource_class_attr_error.hlsl          | 16 ++++++----------
 .../SemaHLSL/resource_binding_attr_error.hlsl    |  2 +-
 .../resource_binding_attr_error_resource.hlsl    | 10 +++++-----
 .../resource_binding_attr_error_udt.hlsl         | 10 +++++-----
 8 files changed, 30 insertions(+), 37 deletions(-)

diff --git a/clang/include/clang/Sema/SemaHLSL.h b/clang/include/clang/Sema/SemaHLSL.h
index f340ed367f8cf3..46eb14321c2740 100644
--- a/clang/include/clang/Sema/SemaHLSL.h
+++ b/clang/include/clang/Sema/SemaHLSL.h
@@ -28,6 +28,12 @@ class IdentifierInfo;
 class ParsedAttr;
 class Scope;
 
+// FIXME: This can be hidden (as static function in SemaHLSL.cpp) once we no
+// longer need to create builtin buffer types in HLSLExternalSemaSource.
+bool CreateHLSLAttributedResourceType(Sema &S, QualType Wrapped,
+                                      llvm::SmallVector<const Attr *> &AttrList,
+                                      QualType &ResType);
+
 class SemaHLSL : public SemaBase {
 public:
   SemaHLSL(Sema &S);
@@ -78,13 +84,6 @@ class SemaHLSL : public SemaBase {
 
   QualType getInoutParameterType(QualType Ty);
 
-  // FIXME: This can be hidden (as static function in SemaHLSL.cpp) once we no
-  // longer need to create builtin buffer types in HLSLExternalSemaSource.
-  static bool
-  CreateHLSLAttributedResourceType(Sema &S, QualType Wrapped,
-                                   llvm::SmallVector<const Attr *> &AttrList,
-                                   QualType &ResType);
-
 private:
   // HLSL resource type attributes need to be processed all at once.
   // This is a list to collect them.
diff --git a/clang/lib/Sema/HLSLExternalSemaSource.cpp b/clang/lib/Sema/HLSLExternalSemaSource.cpp
index 37d24eefb5e66c..071e64fe56d48a 100644
--- a/clang/lib/Sema/HLSLExternalSemaSource.cpp
+++ b/clang/lib/Sema/HLSLExternalSemaSource.cpp
@@ -129,10 +129,8 @@ struct BuiltinTypeDeclBuilder {
         IsROV ? HLSLROVAttr::CreateImplicit(Record->getASTContext()) : nullptr};
     Attr *ResourceAttr =
         HLSLResourceAttr::CreateImplicit(Record->getASTContext(), RK);
-    if (SemaHLSL::CreateHLSLAttributedResourceType(S, Ty, Attrs,
-                                                   AttributedResTy)) {
+    if (CreateHLSLAttributedResourceType(S, Ty, Attrs, AttributedResTy))
       addMemberVariable("h", AttributedResTy, {ResourceAttr}, Access);
-    }
     return *this;
   }
 
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index c2f52f49e10398..d69960fffc812b 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -562,7 +562,7 @@ void SemaHLSL::handleShaderAttr(Decl *D, const ParsedAttr &AL) {
     D->addAttr(NewAttr);
 }
 
-bool SemaHLSL::CreateHLSLAttributedResourceType(
+bool clang::CreateHLSLAttributedResourceType(
     Sema &S, QualType Wrapped, llvm::SmallVector<const Attr *> &AttrList,
     QualType &ResType) {
   assert(AttrList.size() && "expected list of resource attributes");
@@ -673,7 +673,7 @@ SemaHLSL::TakeLocForHLSLAttribute(const HLSLAttributedResourceType *RT) {
   auto I = LocsForHLSLAttributedResources.find(RT);
   if (I != LocsForHLSLAttributedResources.end()) {
     SourceLocation Loc = I->second;
-    LocsForHLSLAttributedResources.erase(RT);
+    LocsForHLSLAttributedResources.erase(I);
     return Loc;
   }
   return SourceLocation();
diff --git a/clang/test/ParserHLSL/hlsl_resource_class_attr.hlsl b/clang/test/ParserHLSL/hlsl_resource_class_attr.hlsl
index 2e25e58d4253e8..f11a64d33839bd 100644
--- a/clang/test/ParserHLSL/hlsl_resource_class_attr.hlsl
+++ b/clang/test/ParserHLSL/hlsl_resource_class_attr.hlsl
@@ -16,17 +16,17 @@ void f() {
 }
 
 // CHECK: ClassTemplateDecl 0x{{[0-9a-f]+}} <line:23:1, line:25:1> line:23:29 MyBuffer2
-// CHECK: TemplateTypeParmDecl 0x{{[0-9a-f]+}} <col:10, col:19> col:19 referenced typename depth 0 index 0 T
+// CHECK: TemplateTypeParmDecl 0x{{[0-9a-f]+}} <col:10, col:19> col:19 typename depth 0 index 0 T
 // CHECK: CXXRecordDecl 0x{{[0-9a-f]+}} <col:22, line:25:1> line:23:29 struct MyBuffer2 definition
 // CHECK: CXXRecordDecl 0x{{[0-9a-f]+}} <col:22, col:29> col:29 implicit struct MyBuffer2
-// CHECK: FieldDecl 0x{{[0-9a-f]+}} <line:24:3, col:35> col:35 h 'T {{\[\[}}hlsl::resource_class(UAV)]]':'T'
+// CHECK: FieldDecl 0x{{[0-9a-f]+}} <line:24:3, col:51> col:51 h '__hlsl_resource_t {{\[\[}}hlsl::resource_class(UAV)]]':'__hlsl_resource_t'
 template<typename T> struct MyBuffer2 {
-  T [[hlsl::resource_class(UAV)]] h;
+  __hlsl_resource_t [[hlsl::resource_class(UAV)]] h;
 };
 
 // CHECK: ClassTemplateSpecializationDecl 0x{{[0-9a-f]+}} <line:23:1, line:25:1> line:23:29 struct MyBuffer2 definition implicit_instantiation
 // CHECK: TemplateArgument type 'float'
 // CHECK: BuiltinType 0x{{[0-9a-f]+}} 'float'
 // CHECK: CXXRecordDecl 0x{{[0-9a-f]+}} <col:22, col:29> col:29 implicit struct MyBuffer2
-// CHECK: FieldDecl 0x{{[0-9a-f]+}} <line:24:3, col:35> col:35 h 'float {{\[\[}}hlsl::resource_class(UAV)]]':'float'
+// CHECK: FieldDecl 0x{{[0-9a-f]+}} <line:24:3, col:51> col:51 h '__hlsl_resource_t {{\[\[}}hlsl::resource_class(UAV)]]':'__hlsl_resource_t'
 MyBuffer2<float> myBuffer2;
diff --git a/clang/test/ParserHLSL/hlsl_resource_class_attr_error.hlsl b/clang/test/ParserHLSL/hlsl_resource_class_attr_error.hlsl
index bb0e9e4621593f..06e607d7462c63 100644
--- a/clang/test/ParserHLSL/hlsl_resource_class_attr_error.hlsl
+++ b/clang/test/ParserHLSL/hlsl_resource_class_attr_error.hlsl
@@ -1,23 +1,19 @@
 // RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-compute -x hlsl -o - %s -verify
 
-struct SomeType {
-  int i;  
-};
-
 // expected-error at +1{{'resource_class' attribute cannot be applied to a declaration}}
-[[hlsl::resource_class(UAV)]] SomeType e0;
+[[hlsl::resource_class(UAV)]] __hlsl_resource_t e0;
 
 // expected-error at +1{{'resource_class' attribute takes one argument}}
-SomeType [[hlsl::resource_class()]] e1;
+__hlsl_resource_t [[hlsl::resource_class()]] e1;
 
 // expected-warning at +1{{ResourceClass attribute argument not supported: gibberish}}
-SomeType [[hlsl::resource_class(gibberish)]] e2;
+__hlsl_resource_t [[hlsl::resource_class(gibberish)]] e2;
 
 // expected-warning at +1{{attribute 'resource_class' is already applied with different arguments}}
-SomeType [[hlsl::resource_class(SRV)]] [[hlsl::resource_class(UAV)]] e3;
+__hlsl_resource_t [[hlsl::resource_class(SRV)]] [[hlsl::resource_class(UAV)]] e3;
 
 // duplicate attribute with the same meaning - no error
-SomeType [[hlsl::resource_class(SRV)]] [[hlsl::resource_class(SRV)]] e4;
+__hlsl_resource_t [[hlsl::resource_class(SRV)]] [[hlsl::resource_class(SRV)]] e4;
 
 // expected-error at +1{{'resource_class' attribute takes one argument}}
-SomeType [[hlsl::resource_class(SRV, "aa")]] e5;
+__hlsl_resource_t [[hlsl::resource_class(SRV, "aa")]] e5;
diff --git a/clang/test/SemaHLSL/resource_binding_attr_error.hlsl b/clang/test/SemaHLSL/resource_binding_attr_error.hlsl
index 9a0474730ed17d..cb728dca838c3b 100644
--- a/clang/test/SemaHLSL/resource_binding_attr_error.hlsl
+++ b/clang/test/SemaHLSL/resource_binding_attr_error.hlsl
@@ -2,7 +2,7 @@
 
 template<typename T>
 struct MyTemplatedSRV {
-  T [[hlsl::resource_class(SRV)]] x;
+  __hlsl_resource_t [[hlsl::resource_class(SRV)]] x;
 };
 
 // valid, The register keyword in this statement isn't binding a resource, rather it is
diff --git a/clang/test/SemaHLSL/resource_binding_attr_error_resource.hlsl b/clang/test/SemaHLSL/resource_binding_attr_error_resource.hlsl
index 6e9df45da48057..4b6af47c0ab725 100644
--- a/clang/test/SemaHLSL/resource_binding_attr_error_resource.hlsl
+++ b/clang/test/SemaHLSL/resource_binding_attr_error_resource.hlsl
@@ -6,23 +6,23 @@
 
 template<typename T>
 struct MyTemplatedSRV {
-  T [[hlsl::resource_class(SRV)]] x;
+  __hlsl_resource_t [[hlsl::resource_class(SRV)]] x;
 };
 
 struct MySRV {
-  int [[hlsl::resource_class(SRV)]] x;
+  __hlsl_resource_t [[hlsl::resource_class(SRV)]] x;
 };
 
 struct MySampler {
-  int [[hlsl::resource_class(Sampler)]] x;
+  __hlsl_resource_t [[hlsl::resource_class(Sampler)]] x;
 };
 
 struct MyUAV {
-  int [[hlsl::resource_class(UAV)]] x;
+  __hlsl_resource_t [[hlsl::resource_class(UAV)]] x;
 };
 
 struct MyCBuffer {
-  int [[hlsl::resource_class(CBuffer)]] x;
+  __hlsl_resource_t [[hlsl::resource_class(CBuffer)]] x;
 };
 
 
diff --git a/clang/test/SemaHLSL/resource_binding_attr_error_udt.hlsl b/clang/test/SemaHLSL/resource_binding_attr_error_udt.hlsl
index 8bc20f72b0d0b3..ea2d576e4cca55 100644
--- a/clang/test/SemaHLSL/resource_binding_attr_error_udt.hlsl
+++ b/clang/test/SemaHLSL/resource_binding_attr_error_udt.hlsl
@@ -2,23 +2,23 @@
 
 template<typename T>
 struct MyTemplatedUAV {
-  T [[hlsl::resource_class(UAV)]] x;
+  __hlsl_resource_t [[hlsl::resource_class(UAV)]] x;
 };
 
 struct MySRV {
-  int [[hlsl::resource_class(SRV)]] x;
+  __hlsl_resource_t [[hlsl::resource_class(SRV)]] x;
 };
 
 struct MySampler {
-  int [[hlsl::resource_class(Sampler)]] x;
+  __hlsl_resource_t [[hlsl::resource_class(Sampler)]] x;
 };
 
 struct MyUAV {
-  int [[hlsl::resource_class(UAV)]] x;
+  __hlsl_resource_t [[hlsl::resource_class(UAV)]] x;
 };
 
 struct MyCBuffer {
-  int [[hlsl::resource_class(CBuffer)]] x;
+  __hlsl_resource_t [[hlsl::resource_class(CBuffer)]] x;
 };
 
 // Valid: f is skipped, SRVBuf is bound to t0, UAVBuf is bound to u0

>From af82e92757c764e645bb0cc6747b73db20008855 Mon Sep 17 00:00:00 2001
From: Helena Kotas <hekotas at microsoft.com>
Date: Wed, 4 Sep 2024 21:48:37 -0700
Subject: [PATCH 5/6] code review feedback

---
 .../clang/Basic/DiagnosticSemaKinds.td        |  2 +-
 clang/include/clang/Sema/SemaHLSL.h           |  2 +-
 clang/lib/AST/TypePrinter.cpp                 |  8 +++---
 clang/lib/Sema/SemaHLSL.cpp                   | 28 +++++++++----------
 4 files changed, 20 insertions(+), 20 deletions(-)

diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 4f522f68f080aa..ad28d734772eb1 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -12364,7 +12364,7 @@ def err_hlsl_packoffset_cross_reg_boundary : Error<"packoffset cannot cross regi
 def err_hlsl_packoffset_alignment_mismatch : Error<"packoffset at 'y' not match alignment %0 required by %1">;
 def err_hlsl_pointers_unsupported : Error<
   "%select{pointers|references}0 are unsupported in HLSL">;
-def err_missing_resource_class : Error<"HLSL resource needs to have [[hlsl::resource_class()]] attribute">;
+def err_hlsl_missing_resource_class : Error<"HLSL resource needs to have [[hlsl::resource_class()]] attribute">;
 
 def err_hlsl_operator_unsupported : Error<
   "the '%select{&|*|->}0' operator is unsupported in HLSL">;
diff --git a/clang/include/clang/Sema/SemaHLSL.h b/clang/include/clang/Sema/SemaHLSL.h
index 46eb14321c2740..cdff1d2f66dc1f 100644
--- a/clang/include/clang/Sema/SemaHLSL.h
+++ b/clang/include/clang/Sema/SemaHLSL.h
@@ -31,7 +31,7 @@ class Scope;
 // FIXME: This can be hidden (as static function in SemaHLSL.cpp) once we no
 // longer need to create builtin buffer types in HLSLExternalSemaSource.
 bool CreateHLSLAttributedResourceType(Sema &S, QualType Wrapped,
-                                      llvm::SmallVector<const Attr *> &AttrList,
+                                      ArrayRef<const Attr *> AttrList,
                                       QualType &ResType);
 
 class SemaHLSL : public SemaBase {
diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp
index 27b251a5575855..3bef9370e621ce 100644
--- a/clang/lib/AST/TypePrinter.cpp
+++ b/clang/lib/AST/TypePrinter.cpp
@@ -2066,8 +2066,11 @@ void TypePrinter::printBTFTagAttributedAfter(const BTFTagAttributedType *T,
 void TypePrinter::printHLSLAttributedResourceBefore(
     const HLSLAttributedResourceType *T, raw_ostream &OS) {
   printBefore(T->getWrappedType(), OS);
-  printAfter(T->getWrappedType(), OS);
+}
 
+void TypePrinter::printHLSLAttributedResourceAfter(
+    const HLSLAttributedResourceType *T, raw_ostream &OS) {
+  printAfter(T->getWrappedType(), OS);
   const HLSLAttributedResourceType::Attributes &Attrs = T->getAttrs();
   OS << " [[hlsl::resource_class("
      << HLSLResourceClassAttr::ConvertResourceClassToStr(Attrs.ResourceClass)
@@ -2076,9 +2079,6 @@ void TypePrinter::printHLSLAttributedResourceBefore(
     OS << " [[hlsl::is_rov()]]";
 }
 
-void TypePrinter::printHLSLAttributedResourceAfter(
-    const HLSLAttributedResourceType *T, raw_ostream &OS) {}
-
 void TypePrinter::printObjCInterfaceBefore(const ObjCInterfaceType *T,
                                            raw_ostream &OS) {
   OS << T->getDecl()->getName();
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index d69960fffc812b..71a23d34853897 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -562,27 +562,27 @@ void SemaHLSL::handleShaderAttr(Decl *D, const ParsedAttr &AL) {
     D->addAttr(NewAttr);
 }
 
-bool clang::CreateHLSLAttributedResourceType(
-    Sema &S, QualType Wrapped, llvm::SmallVector<const Attr *> &AttrList,
-    QualType &ResType) {
+bool clang::CreateHLSLAttributedResourceType(Sema &S, QualType Wrapped,
+                                             ArrayRef<const Attr *> AttrList,
+                                             QualType &ResType) {
   assert(AttrList.size() && "expected list of resource attributes");
 
   QualType Contained = QualType();
   HLSLAttributedResourceType::Attributes ResAttrs = {};
 
-  bool hasResourceClass = false;
-  for (auto *Attr : AttrList) {
-    if (!Attr)
+  bool HasResourceClass = false;
+  for (const Attr *A : AttrList) {
+    if (!A)
       continue;
-    switch (Attr->getKind()) {
+    switch (A->getKind()) {
     case attr::HLSLResourceClass: {
       llvm::dxil::ResourceClass RC =
-          dyn_cast<HLSLResourceClassAttr>(Attr)->getResourceClass();
-      if (!hasResourceClass) {
+          dyn_cast<HLSLResourceClassAttr>(A)->getResourceClass();
+      if (!HasResourceClass) {
         ResAttrs.ResourceClass = RC;
-        hasResourceClass = true;
-      } else if (RC != ResAttrs.ResourceClass) {
-        S.Diag(Attr->getLocation(), diag::warn_duplicate_attribute) << Attr;
+        HasResourceClass = true;
+      } else {
+        S.Diag(A->getLocation(), diag::warn_duplicate_attribute) << A;
         return false;
       }
       break;
@@ -595,9 +595,9 @@ bool clang::CreateHLSLAttributedResourceType(
     }
   }
 
-  if (!hasResourceClass) {
+  if (!HasResourceClass) {
     S.Diag(AttrList.back()->getRange().getEnd(),
-           diag::err_missing_resource_class);
+           diag::err_hlsl_missing_resource_class);
     return false;
   }
 

>From e2b73cc0ab0c7318193f9320288417e485ea48aa Mon Sep 17 00:00:00 2001
From: Helena Kotas <hekotas at microsoft.com>
Date: Thu, 5 Sep 2024 10:47:27 -0700
Subject: [PATCH 6/6] update warning message

---
 clang/lib/Sema/SemaHLSL.cpp                               | 5 ++++-
 clang/test/ParserHLSL/hlsl_resource_class_attr_error.hlsl | 2 +-
 2 files changed, 5 insertions(+), 2 deletions(-)

diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index 71a23d34853897..85582c1e602002 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -582,7 +582,10 @@ bool clang::CreateHLSLAttributedResourceType(Sema &S, QualType Wrapped,
         ResAttrs.ResourceClass = RC;
         HasResourceClass = true;
       } else {
-        S.Diag(A->getLocation(), diag::warn_duplicate_attribute) << A;
+        S.Diag(A->getLocation(), ResAttrs.ResourceClass == RC
+                                     ? diag::warn_duplicate_attribute_exact
+                                     : diag::warn_duplicate_attribute)
+            << A;
         return false;
       }
       break;
diff --git a/clang/test/ParserHLSL/hlsl_resource_class_attr_error.hlsl b/clang/test/ParserHLSL/hlsl_resource_class_attr_error.hlsl
index 06e607d7462c63..01ff1c007e2b57 100644
--- a/clang/test/ParserHLSL/hlsl_resource_class_attr_error.hlsl
+++ b/clang/test/ParserHLSL/hlsl_resource_class_attr_error.hlsl
@@ -12,7 +12,7 @@ __hlsl_resource_t [[hlsl::resource_class(gibberish)]] e2;
 // expected-warning at +1{{attribute 'resource_class' is already applied with different arguments}}
 __hlsl_resource_t [[hlsl::resource_class(SRV)]] [[hlsl::resource_class(UAV)]] e3;
 
-// duplicate attribute with the same meaning - no error
+// expected-warning at +1{{attribute 'resource_class' is already applied}}
 __hlsl_resource_t [[hlsl::resource_class(SRV)]] [[hlsl::resource_class(SRV)]] e4;
 
 // expected-error at +1{{'resource_class' attribute takes one argument}}



More information about the cfe-commits mailing list