https://github.com/inbelic updated 
https://github.com/llvm/llvm-project/pull/182101

>From 7e0694345e7181eb388f3b136b8d0fa2ce8e5d69 Mon Sep 17 00:00:00 2001
From: Finn Plummer <[email protected]>
Date: Tue, 17 Feb 2026 11:54:04 -0800
Subject: [PATCH 1/3] [SemaHLSL] Emit a warning if local resource refer to
 non-unique global resources

---
 .../clang/Basic/DiagnosticSemaKinds.td        |  3 +
 clang/include/clang/Sema/SemaHLSL.h           | 18 +++++
 clang/lib/Sema/SemaHLSL.cpp                   | 68 ++++++++++++++++++-
 .../SemaHLSL/local_resource_bindings.hlsl     | 56 +++++++++++++++
 .../local_resource_bindings_errs.hlsl         | 49 +++++++++++++
 5 files changed, 193 insertions(+), 1 deletion(-)
 create mode 100644 clang/test/SemaHLSL/local_resource_bindings.hlsl
 create mode 100644 clang/test/SemaHLSL/local_resource_bindings_errs.hlsl

diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 85a023435ba23..3d69eced857b6 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -13513,6 +13513,9 @@ def 
err_hlsl_incomplete_resource_array_in_function_param: Error<
   "incomplete resource array in a function parameter">;
 def err_hlsl_assign_to_global_resource: Error<
   "assignment to global resource variable %0 is not allowed">;
+def warn_hlsl_assigning_local_resource_is_not_unique
+    : Warning<"assignment of %0 to local resource %1 is not to the same "
+              "unique global resource">;
 
 def err_hlsl_push_constant_unique
     : Error<"cannot have more than one push constant block">;
diff --git a/clang/include/clang/Sema/SemaHLSL.h 
b/clang/include/clang/Sema/SemaHLSL.h
index 020a4dc44ee7f..86748f15b9e76 100644
--- a/clang/include/clang/Sema/SemaHLSL.h
+++ b/clang/include/clang/Sema/SemaHLSL.h
@@ -132,6 +132,8 @@ class SemaHLSL : public SemaBase {
   bool ActOnUninitializedVarDecl(VarDecl *D);
   void ActOnEndOfTranslationUnit(TranslationUnitDecl *TU);
   void CheckEntryPoint(FunctionDecl *FD);
+
+  // Return true if everything is ok; returns false if there was an error.
   bool CheckResourceBinOp(BinaryOperatorKind Opc, Expr *LHSExpr, Expr *RHSExpr,
                           SourceLocation Loc);
 
@@ -234,6 +236,12 @@ class SemaHLSL : public SemaBase {
   // List of all resource bindings
   ResourceBindings Bindings;
 
+  // Map of local resource variables to their assigned global resources.
+  //
+  // The binding can be a nullptr, in which case, the variable has yet to be
+  // initialized or assigned to.
+  llvm::DenseMap<const VarDecl *, const DeclBindingInfo *> Assigns;
+
   // Global declaration collected for the $Globals default constant
   // buffer which will be created at the end of the translation unit.
   llvm::SmallVector<Decl *> DefaultCBufferDecls;
@@ -313,6 +321,16 @@ class SemaHLSL : public SemaBase {
 
   bool initGlobalResourceDecl(VarDecl *VD);
   bool initGlobalResourceArrayDecl(VarDecl *VD);
+
+  // Infer a common global binding info for an Expr
+  //
+  // Returns std::nullopt if the expr refers to non-unique global bindings.
+  // Returns nullptr if it refer to any global binding, otherwise it returns
+  // a reference to the global binding info.
+  std::optional<const DeclBindingInfo *> inferGlobalBinding(Expr *E);
+
+  // Returns true if no diagnostic is reported
+  bool trackLocalResource(VarDecl *VDecl, Expr *E);
 };
 
 } // namespace clang
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index 4271056ad43cc..0e4ce381eae34 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -4685,7 +4685,67 @@ bool SemaHLSL::ActOnUninitializedVarDecl(VarDecl *VD) {
   return false;
 }
 
-// Return true if everything is ok; returns false if there was an error.
+std::optional<const DeclBindingInfo *> SemaHLSL::inferGlobalBinding(Expr *E) {
+  if (auto *Ternary = dyn_cast<ConditionalOperator>(E)) {
+    auto TrueInfo = inferGlobalBinding(Ternary->getTrueExpr());
+    auto FalseInfo = inferGlobalBinding(Ternary->getFalseExpr());
+    if (!TrueInfo || !FalseInfo)
+      return std::nullopt;
+    if (*TrueInfo != *FalseInfo)
+      return std::nullopt;
+    return TrueInfo;
+  }
+
+  if (auto *ASE = dyn_cast<ArraySubscriptExpr>(E))
+    E = ASE->getBase()->IgnoreParenImpCasts();
+
+  if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E->IgnoreParens()))
+    if (VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl())) {
+      const Type *Ty = VD->getType()->getUnqualifiedDesugaredType();
+      if (Ty->isArrayType())
+        Ty = Ty->getArrayElementTypeNoTypeQual();
+
+      if (const auto *AttrResType =
+              HLSLAttributedResourceType::findHandleTypeOnResource(Ty)) {
+        ResourceClass RC = AttrResType->getAttrs().ResourceClass;
+        return Bindings.getDeclBindingInfo(VD, RC);
+      }
+    }
+
+  return nullptr;
+}
+
+bool SemaHLSL::trackLocalResource(VarDecl *VD, Expr *E) {
+  std::optional<const DeclBindingInfo *> ExprBinding = inferGlobalBinding(E);
+  if (!ExprBinding) {
+    SemaRef.Diag(E->getBeginLoc(),
+                 diag::warn_hlsl_assigning_local_resource_is_not_unique)
+        << E << VD;
+    return false;
+  }
+
+  if (*ExprBinding == nullptr)
+    return true; // No binding could be inferred to track, return without error
+
+  auto PrevBinding = Assigns.find(VD);
+  if (PrevBinding == Assigns.end()) {
+    // No previous binding recorded, simply record the new assignment
+    Assigns.insert({VD, *ExprBinding});
+    return true;
+  }
+
+  // Otherwise, warn if the assignment implies different resource bindings
+  if (*ExprBinding != PrevBinding->second) {
+    SemaRef.Diag(E->getBeginLoc(),
+                 diag::warn_hlsl_assigning_local_resource_is_not_unique)
+        << E << VD;
+    SemaRef.Diag(VD->getLocation(), diag::note_var_declared_here) << VD;
+    return false;
+  }
+
+  return true;
+}
+
 bool SemaHLSL::CheckResourceBinOp(BinaryOperatorKind Opc, Expr *LHSExpr,
                                   Expr *RHSExpr, SourceLocation Loc) {
   assert((LHSExpr->getType()->isHLSLResourceRecord() ||
@@ -4708,6 +4768,8 @@ bool SemaHLSL::CheckResourceBinOp(BinaryOperatorKind Opc, 
Expr *LHSExpr,
         SemaRef.Diag(VD->getLocation(), diag::note_var_declared_here) << VD;
         return false;
       }
+
+      trackLocalResource(VD, RHSExpr);
     }
   }
   return true;
@@ -5312,6 +5374,10 @@ QualType SemaHLSL::checkMatrixComponent(Sema &S, 
QualType baseType,
 }
 
 bool SemaHLSL::handleInitialization(VarDecl *VDecl, Expr *&Init) {
+  // If initializing a local resource, track the resource binding it is using
+  if (VDecl->getType()->isHLSLResourceRecord() && !VDecl->hasGlobalStorage())
+    trackLocalResource(VDecl, Init);
+
   const HLSLVkConstantIdAttr *ConstIdAttr =
       VDecl->getAttr<HLSLVkConstantIdAttr>();
   if (!ConstIdAttr)
diff --git a/clang/test/SemaHLSL/local_resource_bindings.hlsl 
b/clang/test/SemaHLSL/local_resource_bindings.hlsl
new file mode 100644
index 0000000000000..3059452b49ef0
--- /dev/null
+++ b/clang/test/SemaHLSL/local_resource_bindings.hlsl
@@ -0,0 +1,56 @@
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-library -verify %s
+
+// expected-no-diagnostics
+
+RWBuffer<int> In : register(u0);
+RWStructuredBuffer<int> Out0 : register(u1);
+RWStructuredBuffer<int> Out1 : register(u2);
+RWStructuredBuffer<int> OutArr[];
+
+cbuffer c {
+    bool cond;
+};
+
+void no_initial_assignment(int idx) {
+    RWStructuredBuffer<int> Out;
+    if (cond) {
+        Out = Out1;
+    }
+    Out[idx] = In[idx];
+}
+
+void same_assignment(int idx) {
+    RWStructuredBuffer<int> Out = Out1;
+    if (cond) {
+        Out = Out1;
+    }
+    Out[idx] = In[idx];
+}
+
+void conditional_initialization_with_index(int idx) {
+    RWStructuredBuffer<int> Out = cond ? OutArr[0] : OutArr[1];
+    Out[idx] = In[idx];
+}
+
+void conditional_assignment_with_index(int idx) {
+    RWStructuredBuffer<int> Out;
+       if (cond) {
+               Out = OutArr[0];
+       } else {
+               Out = OutArr[1];
+       }
+    Out[idx] = In[idx];
+}
+
+void reassignment(int idx) {
+    RWStructuredBuffer<int> Out = Out0;
+       if (cond) {
+               Out = Out0;
+       }
+       Out[idx] = In[idx];
+}
+
+void conditional_result_in_same(int idx) {
+    RWStructuredBuffer<int> Out = cond ? Out0 : Out0;
+       Out[idx] = In[idx];
+}
diff --git a/clang/test/SemaHLSL/local_resource_bindings_errs.hlsl 
b/clang/test/SemaHLSL/local_resource_bindings_errs.hlsl
new file mode 100644
index 0000000000000..3be8268ec0505
--- /dev/null
+++ b/clang/test/SemaHLSL/local_resource_bindings_errs.hlsl
@@ -0,0 +1,49 @@
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-library -verify %s
+
+RWBuffer<int> In : register(u0);
+RWStructuredBuffer<int> Out0 : register(u1);
+RWStructuredBuffer<int> Out1 : register(u2);
+RWStructuredBuffer<int> OutArr[];
+
+cbuffer c {
+    bool cond;
+};
+
+void conditional_initialization(int idx) {
+    // expected-warning@+1 {{assignment of 'cond ? Out0 : Out1' to local 
resource 'Out' is not to the same unique global resource}}
+    RWStructuredBuffer<int> Out = cond ? Out0 : Out1;
+    Out[idx] = In[idx];
+}
+
+void branched_assignment(int idx) {
+    RWStructuredBuffer<int> Out = Out0; // expected-note {{variable 'Out' is 
declared here}}
+    if (cond) {
+        // expected-warning@+1 {{assignment of 'Out1' to local resource 'Out' 
is not to the same unique global resource}}
+        Out = Out1;
+    }
+    Out[idx] = In[idx];
+}
+
+void branched_assignment_with_array(int idx) {
+    RWStructuredBuffer<int> Out = Out0; // expected-note {{variable 'Out' is 
declared here}}
+    if (cond) {
+        // expected-warning@+1 {{assignment of 'OutArr[0]' to local resource 
'Out' is not to the same unique global resource}}
+        Out = OutArr[0];
+    }
+    Out[idx] = In[idx];
+}
+
+void conditional_assignment(int idx) {
+    RWStructuredBuffer<int> Out;
+    // expected-warning@+1 {{assignment of 'cond ? Out0 : Out1' to local 
resource 'Out' is not to the same unique global resource}}
+    Out = cond ? Out0 : Out1;
+    Out[idx] = In[idx];
+}
+
+static RWStructuredBuffer<int> StaticOut;
+
+void static_conditional_assignment(int idx) {
+    // expected-warning@+1 {{assignment of 'cond ? Out0 : Out1' to local 
resource 'StaticOut' is not to the same unique global resource}}
+    StaticOut = cond ? Out0 : Out1;
+    StaticOut[idx] = In[idx];
+}

>From b7b5ab16cf2fcf384d534ae1e3639b6486d26635 Mon Sep 17 00:00:00 2001
From: Finn Plummer <[email protected]>
Date: Thu, 19 Feb 2026 14:59:45 -0800
Subject: [PATCH 2/3] review: add assignment to uninitialized test

- no warnings generated
---
 clang/test/SemaHLSL/local_resource_bindings.hlsl | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/clang/test/SemaHLSL/local_resource_bindings.hlsl 
b/clang/test/SemaHLSL/local_resource_bindings.hlsl
index 3059452b49ef0..a7f28018516a6 100644
--- a/clang/test/SemaHLSL/local_resource_bindings.hlsl
+++ b/clang/test/SemaHLSL/local_resource_bindings.hlsl
@@ -19,6 +19,12 @@ void no_initial_assignment(int idx) {
     Out[idx] = In[idx];
 }
 
+void assignment_to_uninitialized(int idx) {
+    RWStructuredBuffer<int> Out;
+    Out = Out;
+    Out[idx] = In[idx];
+}
+
 void same_assignment(int idx) {
     RWStructuredBuffer<int> Out = Out1;
     if (cond) {

>From 605af718df76ab15d89f1555648db0fdae2ba58a Mon Sep 17 00:00:00 2001
From: Finn Plummer <[email protected]>
Date: Thu, 19 Feb 2026 15:01:02 -0800
Subject: [PATCH 3/3] review: remove unused return value

---
 clang/include/clang/Sema/SemaHLSL.h | 3 +--
 clang/lib/Sema/SemaHLSL.cpp         | 2 +-
 2 files changed, 2 insertions(+), 3 deletions(-)

diff --git a/clang/include/clang/Sema/SemaHLSL.h 
b/clang/include/clang/Sema/SemaHLSL.h
index 86748f15b9e76..a6a38531ac284 100644
--- a/clang/include/clang/Sema/SemaHLSL.h
+++ b/clang/include/clang/Sema/SemaHLSL.h
@@ -329,8 +329,7 @@ class SemaHLSL : public SemaBase {
   // a reference to the global binding info.
   std::optional<const DeclBindingInfo *> inferGlobalBinding(Expr *E);
 
-  // Returns true if no diagnostic is reported
-  bool trackLocalResource(VarDecl *VDecl, Expr *E);
+  void trackLocalResource(VarDecl *VDecl, Expr *E);
 };
 
 } // namespace clang
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index ddf6b8a522e9d..8fce555534244 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -4716,7 +4716,7 @@ std::optional<const DeclBindingInfo *> 
SemaHLSL::inferGlobalBinding(Expr *E) {
   return nullptr;
 }
 
-bool SemaHLSL::trackLocalResource(VarDecl *VD, Expr *E) {
+void SemaHLSL::trackLocalResource(VarDecl *VD, Expr *E) {
   std::optional<const DeclBindingInfo *> ExprBinding = inferGlobalBinding(E);
   if (!ExprBinding) {
     SemaRef.Diag(E->getBeginLoc(),

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

Reply via email to