[clang] [HLSL] Disallow writing to readonly resources (PR #147806)

Ashley Coleman via cfe-commits cfe-commits at lists.llvm.org
Fri Jul 11 12:31:28 PDT 2025


https://github.com/V-FEXrt updated https://github.com/llvm/llvm-project/pull/147806

>From 9abd7ddf395cb612ff2bca833a70394ffb241885 Mon Sep 17 00:00:00 2001
From: Ashley Coleman <ascoleman at microsoft.com>
Date: Wed, 9 Jul 2025 12:48:51 -0600
Subject: [PATCH 1/6] [HLSL] Disallow writing to readonly resources

---
 clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp | 15 ++++++++++++++-
 clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h   |  1 +
 clang/test/SemaHLSL/BuiltIns/Buffers.hlsl     |  4 ++++
 3 files changed, 19 insertions(+), 1 deletion(-)

diff --git a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
index e5c6220bfb47d..7c08a917f24be 100644
--- a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
+++ b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
@@ -613,6 +613,17 @@ BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addHandleMember(
     ResourceClass RC, bool IsROV, bool RawBuffer, AccessSpecifier Access) {
   assert(!Record->isCompleteDefinition() && "record is already complete");
 
+  switch (RC) {
+  case llvm::dxil::ResourceClass::UAV:
+    IsConstResourceClass = false;
+    break;
+  case llvm::dxil::ResourceClass::SRV:
+  case llvm::dxil::ResourceClass::CBuffer:
+  case llvm::dxil::ResourceClass::Sampler:
+    IsConstResourceClass = true;
+    break;
+  };
+
   ASTContext &Ctx = SemaRef.getASTContext();
   TypeSourceInfo *ElementTypeInfo =
       Ctx.getTrivialTypeSourceInfo(getHandleElementType(), SourceLocation());
@@ -697,7 +708,9 @@ BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addArraySubscriptOperators() {
       AST.DeclarationNames.getCXXOperatorName(OO_Subscript);
 
   addHandleAccessFunction(Subscript, /*IsConst=*/true, /*IsRef=*/true);
-  addHandleAccessFunction(Subscript, /*IsConst=*/false, /*IsRef=*/true);
+  if (!IsConstResourceClass)
+    addHandleAccessFunction(Subscript, /*IsConst=*/false, /*IsRef=*/true);
+
   return *this;
 }
 
diff --git a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h
index a52e2938104c7..d8fac3cebc94a 100644
--- a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h
+++ b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h
@@ -52,6 +52,7 @@ class BuiltinTypeDeclBuilder {
   ClassTemplateDecl *PrevTemplate = nullptr;
   NamespaceDecl *HLSLNamespace = nullptr;
   llvm::StringMap<FieldDecl *> Fields;
+  bool IsConstResourceClass = false;
 
 public:
   friend struct TemplateParameterListBuilder;
diff --git a/clang/test/SemaHLSL/BuiltIns/Buffers.hlsl b/clang/test/SemaHLSL/BuiltIns/Buffers.hlsl
index 477a16a454a9c..7c4a6d7abc538 100644
--- a/clang/test/SemaHLSL/BuiltIns/Buffers.hlsl
+++ b/clang/test/SemaHLSL/BuiltIns/Buffers.hlsl
@@ -111,4 +111,8 @@ Buffer<threeDoubles> BufferErr3;
 void main() {
   (void)Buff.__handle; // expected-error {{'__handle' is a private member of 'hlsl::Buffer<vector<float, 3>>'}}
   // expected-note@* {{implicitly declared private here}}
+
+  // expected-error at +2 {{cannot assign to return value because function 'operator[]' returns a const value}}
+  // expected-note@*:* {{(frontend): function 'operator[]' which returns const-qualified type 'vector<float const hlsl_device &, 3>' declared here}}
+  Buff[0] = 0.0;
 }

>From 4494d423a2e71c53dcbb49818e96bc09d77db7fa Mon Sep 17 00:00:00 2001
From: Ashley Coleman <ascoleman at microsoft.com>
Date: Wed, 9 Jul 2025 13:15:51 -0600
Subject: [PATCH 2/6] Finish tests

---
 clang/test/SemaHLSL/BuiltIns/Buffers.hlsl           | 2 +-
 clang/test/SemaHLSL/BuiltIns/StructuredBuffers.hlsl | 4 ++++
 2 files changed, 5 insertions(+), 1 deletion(-)

diff --git a/clang/test/SemaHLSL/BuiltIns/Buffers.hlsl b/clang/test/SemaHLSL/BuiltIns/Buffers.hlsl
index 7c4a6d7abc538..d7c6876d3b9e3 100644
--- a/clang/test/SemaHLSL/BuiltIns/Buffers.hlsl
+++ b/clang/test/SemaHLSL/BuiltIns/Buffers.hlsl
@@ -113,6 +113,6 @@ void main() {
   // expected-note@* {{implicitly declared private here}}
 
   // expected-error at +2 {{cannot assign to return value because function 'operator[]' returns a const value}}
-  // expected-note@*:* {{(frontend): function 'operator[]' which returns const-qualified type 'vector<float const hlsl_device &, 3>' declared here}}
+  // expected-note@* {{function 'operator[]' which returns const-qualified type 'vector<float const hlsl_device &, 3>' declared here}}
   Buff[0] = 0.0;
 }
diff --git a/clang/test/SemaHLSL/BuiltIns/StructuredBuffers.hlsl b/clang/test/SemaHLSL/BuiltIns/StructuredBuffers.hlsl
index bf541f4a07da7..fbd9288590adc 100644
--- a/clang/test/SemaHLSL/BuiltIns/StructuredBuffers.hlsl
+++ b/clang/test/SemaHLSL/BuiltIns/StructuredBuffers.hlsl
@@ -28,4 +28,8 @@ StructuredBuffer<Empty> BufferErr4;
 void main() {
   (void)Buff.__handle; // expected-error {{'__handle' is a private member of 'hlsl::StructuredBuffer<vector<float, 3>>'}}
   // expected-note@* {{implicitly declared private here}}
+
+  // expected-error at +2 {{cannot assign to return value because function 'operator[]' returns a const value}}
+  // expected-note@* {{function 'operator[]' which returns const-qualified type 'vector<float const hlsl_device &, 3>' declared here}}
+  Buff[0] = 0.0;
 }

>From eeb4d59ec00a823d0ccad3011aff50d50b2360c3 Mon Sep 17 00:00:00 2001
From: Ashley Coleman <ascoleman at microsoft.com>
Date: Wed, 9 Jul 2025 14:55:55 -0600
Subject: [PATCH 3/6] Address comments

---
 clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp | 15 +++------------
 clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h   |  2 +-
 2 files changed, 4 insertions(+), 13 deletions(-)

diff --git a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
index 7c08a917f24be..cf096bac4001c 100644
--- a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
+++ b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
@@ -613,16 +613,7 @@ BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addHandleMember(
     ResourceClass RC, bool IsROV, bool RawBuffer, AccessSpecifier Access) {
   assert(!Record->isCompleteDefinition() && "record is already complete");
 
-  switch (RC) {
-  case llvm::dxil::ResourceClass::UAV:
-    IsConstResourceClass = false;
-    break;
-  case llvm::dxil::ResourceClass::SRV:
-  case llvm::dxil::ResourceClass::CBuffer:
-  case llvm::dxil::ResourceClass::Sampler:
-    IsConstResourceClass = true;
-    break;
-  };
+  RClass = RC;
 
   ASTContext &Ctx = SemaRef.getASTContext();
   TypeSourceInfo *ElementTypeInfo =
@@ -631,7 +622,7 @@ BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addHandleMember(
   // add handle member with resource type attributes
   QualType AttributedResTy = QualType();
   SmallVector<const Attr *> Attrs = {
-      HLSLResourceClassAttr::CreateImplicit(Ctx, RC),
+      HLSLResourceClassAttr::CreateImplicit(Ctx, RClass),
       IsROV ? HLSLROVAttr::CreateImplicit(Ctx) : nullptr,
       RawBuffer ? HLSLRawBufferAttr::CreateImplicit(Ctx) : nullptr,
       ElementTypeInfo
@@ -708,7 +699,7 @@ BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addArraySubscriptOperators() {
       AST.DeclarationNames.getCXXOperatorName(OO_Subscript);
 
   addHandleAccessFunction(Subscript, /*IsConst=*/true, /*IsRef=*/true);
-  if (!IsConstResourceClass)
+  if (RClass == llvm::dxil::ResourceClass::UAV)
     addHandleAccessFunction(Subscript, /*IsConst=*/false, /*IsRef=*/true);
 
   return *this;
diff --git a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h
index d8fac3cebc94a..426c0550e1c6c 100644
--- a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h
+++ b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h
@@ -52,7 +52,7 @@ class BuiltinTypeDeclBuilder {
   ClassTemplateDecl *PrevTemplate = nullptr;
   NamespaceDecl *HLSLNamespace = nullptr;
   llvm::StringMap<FieldDecl *> Fields;
-  bool IsConstResourceClass = false;
+  ResourceClass RClass;
 
 public:
   friend struct TemplateParameterListBuilder;

>From 86e125a2183d9a1b524fcb228884e10592797791 Mon Sep 17 00:00:00 2001
From: Ashley Coleman <ascoleman at microsoft.com>
Date: Thu, 10 Jul 2025 13:32:24 -0600
Subject: [PATCH 4/6] Fix tests

---
 clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp |  6 ++--
 clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h   |  2 +-
 .../test/AST/HLSL/StructuredBuffers-AST.hlsl  | 36 +++++++++----------
 clang/test/AST/HLSL/TypedBuffers-AST.hlsl     | 31 ++++++++--------
 4 files changed, 37 insertions(+), 38 deletions(-)

diff --git a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
index cf096bac4001c..257fdfd64ecf2 100644
--- a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
+++ b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
@@ -613,7 +613,7 @@ BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addHandleMember(
     ResourceClass RC, bool IsROV, bool RawBuffer, AccessSpecifier Access) {
   assert(!Record->isCompleteDefinition() && "record is already complete");
 
-  RClass = RC;
+  ResClass = RC;
 
   ASTContext &Ctx = SemaRef.getASTContext();
   TypeSourceInfo *ElementTypeInfo =
@@ -622,7 +622,7 @@ BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addHandleMember(
   // add handle member with resource type attributes
   QualType AttributedResTy = QualType();
   SmallVector<const Attr *> Attrs = {
-      HLSLResourceClassAttr::CreateImplicit(Ctx, RClass),
+      HLSLResourceClassAttr::CreateImplicit(Ctx, ResClass),
       IsROV ? HLSLROVAttr::CreateImplicit(Ctx) : nullptr,
       RawBuffer ? HLSLRawBufferAttr::CreateImplicit(Ctx) : nullptr,
       ElementTypeInfo
@@ -699,7 +699,7 @@ BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addArraySubscriptOperators() {
       AST.DeclarationNames.getCXXOperatorName(OO_Subscript);
 
   addHandleAccessFunction(Subscript, /*IsConst=*/true, /*IsRef=*/true);
-  if (RClass == llvm::dxil::ResourceClass::UAV)
+  if (ResClass == llvm::dxil::ResourceClass::UAV)
     addHandleAccessFunction(Subscript, /*IsConst=*/false, /*IsRef=*/true);
 
   return *this;
diff --git a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h
index 426c0550e1c6c..91bf8748d0a45 100644
--- a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h
+++ b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h
@@ -52,7 +52,7 @@ class BuiltinTypeDeclBuilder {
   ClassTemplateDecl *PrevTemplate = nullptr;
   NamespaceDecl *HLSLNamespace = nullptr;
   llvm::StringMap<FieldDecl *> Fields;
-  ResourceClass RClass;
+  ResourceClass ResClass;
 
 public:
   friend struct TemplateParameterListBuilder;
diff --git a/clang/test/AST/HLSL/StructuredBuffers-AST.hlsl b/clang/test/AST/HLSL/StructuredBuffers-AST.hlsl
index b74e183eec9cc..1c8b9c10f5a98 100644
--- a/clang/test/AST/HLSL/StructuredBuffers-AST.hlsl
+++ b/clang/test/AST/HLSL/StructuredBuffers-AST.hlsl
@@ -12,7 +12,7 @@
 //
 // RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-library -x hlsl -ast-dump \
 // RUN:   -DRESOURCE=RWStructuredBuffer %s | FileCheck -DRESOURCE=RWStructuredBuffer \
-// RUN:   -check-prefixes=CHECK,CHECK-UAV,CHECK-SUBSCRIPT,CHECK-COUNTER,CHECK-LOAD %s
+// RUN:   -check-prefixes=CHECK,CHECK-UAV,CHECK-SUBSCRIPT,CHECK-SUBSCRIPT-UAV,CHECK-COUNTER,CHECK-LOAD %s
 //
 // RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-library -x hlsl -ast-dump -DEMPTY \
 // RUN:  -DRESOURCE=AppendStructuredBuffer %s | FileCheck -DRESOURCE=AppendStructuredBuffer \
@@ -36,7 +36,7 @@
 //
 // RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-library -x hlsl -ast-dump \
 // RUN:   -DRESOURCE=RasterizerOrderedStructuredBuffer %s | FileCheck -DRESOURCE=RasterizerOrderedStructuredBuffer \
-// RUN:   -check-prefixes=CHECK,CHECK-UAV,CHECK-ROV,CHECK-SUBSCRIPT,CHECK-LOAD %s
+// RUN:   -check-prefixes=CHECK,CHECK-UAV,CHECK-ROV,CHECK-SUBSCRIPT,CHECK-SUBSCRIPT-UAV,CHECK-LOAD %s
 
 // This test tests two different AST generations for each structured buffer.
 // The "EMPTY" test mode verifies the AST generated by forward declaration
@@ -170,22 +170,22 @@ RESOURCE<float> Buffer;
 // CHECK-SUBSCRIPT-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'Index' 'unsigned int'
 // CHECK-SUBSCRIPT-NEXT: AlwaysInlineAttr {{.*}} Implicit always_inline
 
-// CHECK-SUBSCRIPT-NEXT: CXXMethodDecl {{.*}} operator[] 'hlsl_device element_type &(unsigned int)'
-// CHECK-SUBSCRIPT-NEXT: ParmVarDecl {{.*}} Index 'unsigned int'
-// CHECK-SUBSCRIPT-NEXT: CompoundStmt
-// CHECK-SUBSCRIPT-NEXT: ReturnStmt
-// CHECK-SUBSCRIPT-NEXT: UnaryOperator {{.*}} 'hlsl_device element_type' prefix '*' cannot overflow
-// CHECK-SUBSCRIPT-NEXT: CallExpr {{.*}} 'hlsl_device element_type *'
-// CHECK-SUBSCRIPT-NEXT: ImplicitCastExpr {{.*}} <BuiltinFnToFnPtr>
-// CHECK-SUBSCRIPT-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_resource_getpointer' 'void (...) noexcept'
-// CHECK-SUBSCRIPT-NEXT: MemberExpr {{.*}} '__hlsl_resource_t
-// CHECK-SUBSCRIPT-SAME{LITERAL}: [[hlsl::resource_class(
-// CHECK-SUBSCRIPT-SAME{LITERAL}: [[hlsl::raw_buffer]]
-// CHECK-SUBSCRIPT-SAME{LITERAL}: [[hlsl::contained_type(element_type)]]
-// CHECK-SUBSCRIPT-SAME: ' lvalue .__handle {{.*}}
-// CHECK-SUBSCRIPT-NEXT: CXXThisExpr {{.*}} '[[RESOURCE]]<element_type>' lvalue implicit this
-// CHECK-SUBSCRIPT-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'Index' 'unsigned int'
-// CHECK-SUBSCRIPT-NEXT: AlwaysInlineAttr {{.*}} Implicit always_inline
+// CHECK-SUBSCRIPT-UAV-NEXT: CXXMethodDecl {{.*}} operator[] 'hlsl_device element_type &(unsigned int)'
+// CHECK-SUBSCRIPT-UAV-NEXT: ParmVarDecl {{.*}} Index 'unsigned int'
+// CHECK-SUBSCRIPT-UAV-NEXT: CompoundStmt
+// CHECK-SUBSCRIPT-UAV-NEXT: ReturnStmt
+// CHECK-SUBSCRIPT-UAV-NEXT: UnaryOperator {{.*}} 'hlsl_device element_type' prefix '*' cannot overflow
+// CHECK-SUBSCRIPT-UAV-NEXT: CallExpr {{.*}} 'hlsl_device element_type *'
+// CHECK-SUBSCRIPT-UAV-NEXT: ImplicitCastExpr {{.*}} <BuiltinFnToFnPtr>
+// CHECK-SUBSCRIPT-UAV-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_resource_getpointer' 'void (...) noexcept'
+// CHECK-SUBSCRIPT-UAV-NEXT: MemberExpr {{.*}} '__hlsl_resource_t
+// CHECK-SUBSCRIPT-UAV-SAME{LITERAL}: [[hlsl::resource_class(
+// CHECK-SUBSCRIPT-UAV-SAME{LITERAL}: [[hlsl::raw_buffer]]
+// CHECK-SUBSCRIPT-UAV-SAME{LITERAL}: [[hlsl::contained_type(element_type)]]
+// CHECK-SUBSCRIPT-UAV-SAME: ' lvalue .__handle {{.*}}
+// CHECK-SUBSCRIPT-UAV-NEXT: CXXThisExpr {{.*}} '[[RESOURCE]]<element_type>' lvalue implicit this
+// CHECK-SUBSCRIPT-UAV-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'Index' 'unsigned int'
+// CHECK-SUBSCRIPT-UAV-NEXT: AlwaysInlineAttr {{.*}} Implicit always_inline
 
 // CHECK-NOSUBSCRIPT-NOT: CXXMethodDecl {{.*}} operator[] 'const hlsl_device element_type &(unsigned int) const'
 // CHECK-NOSUBSCRIPT-NOT: CXXMethodDecl {{.*}} operator[] 'hlsl_device element_type &(unsigned int)'
diff --git a/clang/test/AST/HLSL/TypedBuffers-AST.hlsl b/clang/test/AST/HLSL/TypedBuffers-AST.hlsl
index d098e5a323ca7..d6b88e276762e 100644
--- a/clang/test/AST/HLSL/TypedBuffers-AST.hlsl
+++ b/clang/test/AST/HLSL/TypedBuffers-AST.hlsl
@@ -126,7 +126,7 @@ RESOURCE<float> Buffer;
 // CHECK-NEXT: DeclRefExpr {{.*}} 'const char *' ParmVar {{.*}} 'name' 'const char *'
 // CHECK-NEXT: AlwaysInlineAttr
 
-// Subsctript operators
+// Subscript operators
 
 // CHECK: CXXMethodDecl {{.*}} operator[] 'const hlsl_device element_type &(unsigned int) const'
 // CHECK-NEXT: ParmVarDecl {{.*}} Index 'unsigned int'
@@ -145,22 +145,21 @@ RESOURCE<float> Buffer;
 // CHECK-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}}  'Index' 'unsigned int'
 // CHECK-NEXT: AlwaysInlineAttr {{.*}} Implicit always_inline
 
-// CHECK-NEXT: CXXMethodDecl {{.*}} operator[] 'hlsl_device element_type &(unsigned int)'
-// CHECK-NEXT: ParmVarDecl {{.*}} Index 'unsigned int'
-// CHECK-NEXT: CompoundStmt
-// CHECK-NEXT: ReturnStmt
-// CHECK-NEXT: UnaryOperator {{.*}} 'hlsl_device element_type' prefix '*' cannot overflow
-// CHECK-NEXT: CallExpr {{.*}} 'hlsl_device element_type *'
-// CHECK-NEXT: ImplicitCastExpr {{.*}} <BuiltinFnToFnPtr>
-// CHECK-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}}  '__builtin_hlsl_resource_getpointer' 'void (...) noexcept'
-// CHECK-NEXT: MemberExpr {{.*}} '__hlsl_resource_t
+// CHECK-UAV-NEXT: CXXMethodDecl {{.*}} operator[] 'hlsl_device element_type &(unsigned int)'
+// CHECK-UAV-NEXT: ParmVarDecl {{.*}} Index 'unsigned int'
+// CHECK-UAV-NEXT: CompoundStmt
+// CHECK-UAV-NEXT: ReturnStmt
+// CHECK-UAV-NEXT: UnaryOperator {{.*}} 'hlsl_device element_type' prefix '*' cannot overflow
+// CHECK-UAV-NEXT: CallExpr {{.*}} 'hlsl_device element_type *'
+// CHECK-UAV-NEXT: ImplicitCastExpr {{.*}} <BuiltinFnToFnPtr>
+// CHECK-UAV-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}}  '__builtin_hlsl_resource_getpointer' 'void (...) noexcept'
+// CHECK-UAV-NEXT: MemberExpr {{.*}} '__hlsl_resource_t
 // CHECK-UAV-SAME{LITERAL}: [[hlsl::resource_class(UAV)]]
-// CHECK-SRV-SAME{LITERAL}: [[hlsl::resource_class(SRV)]]
-// CHECK-SAME{LITERAL}: [[hlsl::contained_type(element_type)]]
-// CHECK-SAME: ' lvalue .__handle {{.*}}
-// CHECK-NEXT: CXXThisExpr {{.*}} '[[RESOURCE]]<element_type>' lvalue implicit this
-// CHECK-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}}  'Index' 'unsigned int'
-// CHECK-NEXT: AlwaysInlineAttr {{.*}} Implicit always_inline
+// CHECK-UAV-SAME{LITERAL}: [[hlsl::contained_type(element_type)]]
+// CHECK-UAV-SAME: ' lvalue .__handle {{.*}}
+// CHECK-UAV-NEXT: CXXThisExpr {{.*}} '[[RESOURCE]]<element_type>' lvalue implicit this
+// CHECK-UAV-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}}  'Index' 'unsigned int'
+// CHECK-UAV-NEXT: AlwaysInlineAttr {{.*}} Implicit always_inline
 
 // Load method
 

>From fa20c2ae5a165fada082b0a58789ff6d34521d7a Mon Sep 17 00:00:00 2001
From: Ashley Coleman <ascoleman at microsoft.com>
Date: Fri, 11 Jul 2025 13:25:11 -0600
Subject: [PATCH 5/6] Address comments

---
 clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp | 12 ++++++++----
 clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h   |  2 +-
 2 files changed, 9 insertions(+), 5 deletions(-)

diff --git a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
index 257fdfd64ecf2..f66d53f8acdcf 100644
--- a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
+++ b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
@@ -613,8 +613,6 @@ BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addHandleMember(
     ResourceClass RC, bool IsROV, bool RawBuffer, AccessSpecifier Access) {
   assert(!Record->isCompleteDefinition() && "record is already complete");
 
-  ResClass = RC;
-
   ASTContext &Ctx = SemaRef.getASTContext();
   TypeSourceInfo *ElementTypeInfo =
       Ctx.getTrivialTypeSourceInfo(getHandleElementType(), SourceLocation());
@@ -622,7 +620,7 @@ BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addHandleMember(
   // add handle member with resource type attributes
   QualType AttributedResTy = QualType();
   SmallVector<const Attr *> Attrs = {
-      HLSLResourceClassAttr::CreateImplicit(Ctx, ResClass),
+      HLSLResourceClassAttr::CreateImplicit(Ctx, RC),
       IsROV ? HLSLROVAttr::CreateImplicit(Ctx) : nullptr,
       RawBuffer ? HLSLRawBufferAttr::CreateImplicit(Ctx) : nullptr,
       ElementTypeInfo
@@ -699,7 +697,7 @@ BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addArraySubscriptOperators() {
       AST.DeclarationNames.getCXXOperatorName(OO_Subscript);
 
   addHandleAccessFunction(Subscript, /*IsConst=*/true, /*IsRef=*/true);
-  if (ResClass == llvm::dxil::ResourceClass::UAV)
+  if (getResourceAttrs().ResourceClass == llvm::dxil::ResourceClass::UAV)
     addHandleAccessFunction(Subscript, /*IsConst=*/false, /*IsRef=*/true);
 
   return *this;
@@ -742,6 +740,12 @@ QualType BuiltinTypeDeclBuilder::getHandleElementType() {
   return SemaRef.getASTContext().Char8Ty;
 }
 
+HLSLAttributedResourceType::Attributes
+BuiltinTypeDeclBuilder::getResourceAttrs() {
+  QualType HandleType = getResourceHandleField()->getType();
+  return cast<HLSLAttributedResourceType>(HandleType)->getAttrs();
+}
+
 // BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::startDefinition() {
 //   assert(!Record->isCompleteDefinition() && "record is already complete");
 //   Record->startDefinition();
diff --git a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h
index 91bf8748d0a45..5f30efb89febb 100644
--- a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h
+++ b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h
@@ -52,7 +52,6 @@ class BuiltinTypeDeclBuilder {
   ClassTemplateDecl *PrevTemplate = nullptr;
   NamespaceDecl *HLSLNamespace = nullptr;
   llvm::StringMap<FieldDecl *> Fields;
-  ResourceClass ResClass;
 
 public:
   friend struct TemplateParameterListBuilder;
@@ -96,6 +95,7 @@ class BuiltinTypeDeclBuilder {
   QualType getFirstTemplateTypeParam();
   QualType getHandleElementType();
   Expr *getConstantIntExpr(int value);
+  HLSLAttributedResourceType::Attributes getResourceAttrs();
 };
 
 } // namespace hlsl

>From ff8f448b2d75bdccdd76a52531374b36511c825f Mon Sep 17 00:00:00 2001
From: Ashley Coleman <ascoleman at microsoft.com>
Date: Fri, 11 Jul 2025 13:31:04 -0600
Subject: [PATCH 6/6] Make functions const

---
 clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp | 4 ++--
 clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h   | 4 ++--
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
index f66d53f8acdcf..87f9ae07550c2 100644
--- a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
+++ b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
@@ -716,7 +716,7 @@ BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addLoadMethods() {
   return *this;
 }
 
-FieldDecl *BuiltinTypeDeclBuilder::getResourceHandleField() {
+FieldDecl *BuiltinTypeDeclBuilder::getResourceHandleField() const {
   auto I = Fields.find("__handle");
   assert(I != Fields.end() &&
          I->second->getType()->isHLSLAttributedResourceType() &&
@@ -741,7 +741,7 @@ QualType BuiltinTypeDeclBuilder::getHandleElementType() {
 }
 
 HLSLAttributedResourceType::Attributes
-BuiltinTypeDeclBuilder::getResourceAttrs() {
+BuiltinTypeDeclBuilder::getResourceAttrs() const {
   QualType HandleType = getResourceHandleField()->getType();
   return cast<HLSLAttributedResourceType>(HandleType)->getAttrs();
 }
diff --git a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h
index 5f30efb89febb..36c4add20b225 100644
--- a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h
+++ b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h
@@ -91,11 +91,11 @@ class BuiltinTypeDeclBuilder {
   BuiltinTypeDeclBuilder &addConsumeMethod();
 
 private:
-  FieldDecl *getResourceHandleField();
+  FieldDecl *getResourceHandleField() const;
   QualType getFirstTemplateTypeParam();
   QualType getHandleElementType();
   Expr *getConstantIntExpr(int value);
-  HLSLAttributedResourceType::Attributes getResourceAttrs();
+  HLSLAttributedResourceType::Attributes getResourceAttrs() const;
 };
 
 } // namespace hlsl



More information about the cfe-commits mailing list