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
