Author: Helena Kotas
Date: 2026-04-08T09:59:56-07:00
New Revision: eb06b4796c2a53c177516dd45ca63f871fc311bb

URL: 
https://github.com/llvm/llvm-project/commit/eb06b4796c2a53c177516dd45ca63f871fc311bb
DIFF: 
https://github.com/llvm/llvm-project/commit/eb06b4796c2a53c177516dd45ca63f871fc311bb.diff

LOG: [HLSL] Diagnose dynamic indexing of struct arrays for resource access 
(#187132)

Dynamic indexing of structs arrays for resource access is not supported. This 
change implements the diagnostic for this.

Fixes #187131

Added: 
    clang/test/SemaHLSL/Resources/resources-in-struct-array-error.hlsl

Modified: 
    clang/include/clang/Basic/DiagnosticSemaKinds.td
    clang/include/clang/Sema/SemaHLSL.h
    clang/lib/Sema/SemaExprMember.cpp
    clang/lib/Sema/SemaHLSL.cpp

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 1ad4ff7098080..6d2fae551566f 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -13712,6 +13712,9 @@ def err_hlsl_samplecmp_requires_float
 def err_hlsl_gathercmp_invalid_component
     : Error<"gatherCmp%select{Red|Green|Blue|Alpha}0 operations on the Vulkan 
target are not supported; only GatherCmp and GatherCmpRed are allowed">;
 
+def err_hlsl_resource_member_array_access_not_constant
+    : Error<"index for struct array inside cbuffer that contains resources 
must be a constant integer expression">;
+
 // Layout randomization diagnostics.
 def err_non_designated_init_used : Error<
   "a randomized struct can only be initialized with a designated initializer">;

diff  --git a/clang/include/clang/Sema/SemaHLSL.h 
b/clang/include/clang/Sema/SemaHLSL.h
index 6f62fbc635d9c..edb7a8202a80b 100644
--- a/clang/include/clang/Sema/SemaHLSL.h
+++ b/clang/include/clang/Sema/SemaHLSL.h
@@ -131,6 +131,7 @@ class SemaHLSL : public SemaBase {
   void ActOnVariableDeclarator(VarDecl *VD);
   bool ActOnUninitializedVarDecl(VarDecl *D);
   void ActOnEndOfTranslationUnit(TranslationUnitDecl *TU);
+  bool ActOnResourceMemberAccessExpr(MemberExpr *ME);
   void CheckEntryPoint(FunctionDecl *FD);
 
   // Return true if everything is ok; returns false if there was an error.

diff  --git a/clang/lib/Sema/SemaExprMember.cpp 
b/clang/lib/Sema/SemaExprMember.cpp
index ff7c844f66123..a4504410cae28 100644
--- a/clang/lib/Sema/SemaExprMember.cpp
+++ b/clang/lib/Sema/SemaExprMember.cpp
@@ -12,6 +12,7 @@
 #include "clang/AST/DeclCXX.h"
 #include "clang/AST/DeclObjC.h"
 #include "clang/AST/DeclTemplate.h"
+#include "clang/AST/Expr.h"
 #include "clang/AST/ExprCXX.h"
 #include "clang/AST/ExprObjC.h"
 #include "clang/AST/TypeBase.h"
@@ -1737,9 +1738,18 @@ ExprResult Sema::ActOnMemberAccessExpr(Scope *S, Expr 
*Base,
       Base, Base->getType(), OpLoc, IsArrow, SS, TemplateKWLoc,
       FirstQualifierInScope, NameInfo, TemplateArgs, S, &ExtraArgs);
 
-  if (!Res.isInvalid() && isa<MemberExpr>(Res.get()))
-    CheckMemberAccessOfNoDeref(cast<MemberExpr>(Res.get()));
+  if (!Res.isInvalid()) {
+    if (MemberExpr *ME = dyn_cast<MemberExpr>(Res.get())) {
+      CheckMemberAccessOfNoDeref(ME);
 
+      if (getLangOpts().HLSL) {
+        QualType Ty = Res.get()->getType();
+        if (Ty->isHLSLResourceRecord() || Ty->isHLSLResourceRecordArray())
+          if (!HLSL().ActOnResourceMemberAccessExpr(ME))
+            Res = ExprError();
+      }
+    }
+  }
   return Res;
 }
 

diff  --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index 5d7cec49c2b19..a943303149931 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -3068,6 +3068,50 @@ void 
SemaHLSL::ActOnEndOfTranslationUnit(TranslationUnitDecl *TU) {
   diagnoseAvailabilityViolations(TU);
 }
 
+// For resource member access through a global struct array, verify that the
+// array index selecting the struct element is a constant integer expression.
+// Returns false if the member expression is invalid.
+bool SemaHLSL::ActOnResourceMemberAccessExpr(MemberExpr *ME) {
+  assert((ME->getType()->isHLSLResourceRecord() ||
+          ME->getType()->isHLSLResourceRecordArray()) &&
+         "expected member expr to have resource record type or array of them");
+
+  // Walk the AST from MemberExpr to the VarDecl of the parent struct instance
+  // and take note of any non-constant array indexing along the way. If the
+  // VarDecl we find is a global variable, report error if there was any
+  // non-constant array index in the resource member access along the way.
+  const Expr *NonConstIndexExpr = nullptr;
+  const Expr *E = ME->getBase();
+  while (E) {
+    if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) {
+      if (!NonConstIndexExpr)
+        return true;
+
+      const VarDecl *VD = cast<VarDecl>(DRE->getDecl());
+      if (!VD->hasGlobalStorage())
+        return true;
+
+      SemaRef.Diag(NonConstIndexExpr->getExprLoc(),
+                   diag::err_hlsl_resource_member_array_access_not_constant);
+      return false;
+    }
+
+    if (const auto *ASE = dyn_cast<ArraySubscriptExpr>(E)) {
+      const Expr *IdxExpr = ASE->getIdx();
+      if (!IdxExpr->isIntegerConstantExpr(SemaRef.getASTContext()))
+        NonConstIndexExpr = IdxExpr;
+      E = ASE->getBase();
+    } else if (const auto *SubME = dyn_cast<MemberExpr>(E)) {
+      E = SubME->getBase();
+    } else if (const auto *ICE = dyn_cast<ImplicitCastExpr>(E)) {
+      E = ICE->getSubExpr();
+    } else {
+      llvm_unreachable("unexpected expr type in resource member access");
+    }
+  }
+  return true;
+}
+
 void SemaHLSL::diagnoseAvailabilityViolations(TranslationUnitDecl *TU) {
   // Skip running the diagnostics scan if the diagnostic mode is
   // strict (-fhlsl-strict-availability) and the target shader stage is known

diff  --git 
a/clang/test/SemaHLSL/Resources/resources-in-struct-array-error.hlsl 
b/clang/test/SemaHLSL/Resources/resources-in-struct-array-error.hlsl
new file mode 100644
index 0000000000000..e98a73812b773
--- /dev/null
+++ b/clang/test/SemaHLSL/Resources/resources-in-struct-array-error.hlsl
@@ -0,0 +1,27 @@
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-compute 
-finclude-default-header -verify %s
+
+struct A {
+  RWBuffer<float> Buf;
+  RWBuffer<float> ManyBufs[5];
+};
+
+A array[10] : register(u10);
+
+[numthreads(4,1,1)]
+void main(uint GI : SV_GroupThreadID) {
+  
+  // expected-error@+1 {{index for struct array inside cbuffer that contains 
resources must be a constant integer expression}}
+  array[GI].Buf[0] = 1.0f; 
+
+  array[2].Buf[GI] = 2.0f; // ok
+
+  // expected-error@+1 {{index for struct array inside cbuffer that contains 
resources must be a constant integer expression}}
+  array[GI].ManyBufs[3][0] = 3.0f;
+
+  array[1].ManyBufs[GI][0] = 4.0f; // ok
+
+  array[1+1].ManyBufs[GI][0] = 4.0f; // ok
+
+  int x = 3;
+  array[1].ManyBufs[x][0] = 4.0f; // ok
+}


        
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to