[clang] [HLSL][SPIR-V] Add vk::ext_builtin_output attribute (PR #188268)

Nathan Gauër via cfe-commits cfe-commits at lists.llvm.org
Wed Mar 25 06:17:01 PDT 2026


https://github.com/Keenuts updated https://github.com/llvm/llvm-project/pull/188268

>From c7a17b0ccd9a3e7533714a8fc7bbd599fdad4fc7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nathan=20Gau=C3=ABr?= <brioche at google.com>
Date: Tue, 24 Mar 2026 15:49:27 +0100
Subject: [PATCH 1/3] [HLSL][SPIR-V] Add vk::ext_builtin_output attribute

This attribute is similar to the already implemented ext_builtin_input
attribute.
One important bit is the `static` storage class: HLSL uses static
differently than C/C++. This is a known weirdness:
 See https://github.com/microsoft/hlsl-specs/issues/350

In C/C++, when we declare a variable as 'extern', we often expect
another module to declare the symbole. In HLSL, the pipeline will
'declare' the symbol. Hence in this case, we need to emit the
global variable.

Related WG-HLSL:
  https://github.com/llvm/wg-hlsl/blob/main/proposals/0031-semantics.md
---
 clang/include/clang/Basic/AddressSpaces.h     |  1 +
 clang/include/clang/Basic/Attr.td             | 14 ++++++++++
 clang/include/clang/Basic/AttrDocs.td         | 23 ++++++++++++++++
 clang/include/clang/Sema/SemaHLSL.h           |  1 +
 clang/lib/AST/Type.cpp                        |  1 +
 clang/lib/AST/TypePrinter.cpp                 |  2 ++
 clang/lib/Basic/TargetInfo.cpp                |  3 ++-
 clang/lib/Basic/Targets/AArch64.h             |  1 +
 clang/lib/Basic/Targets/AMDGPU.cpp            |  2 ++
 clang/lib/Basic/Targets/DirectX.h             |  1 +
 clang/lib/Basic/Targets/NVPTX.h               |  1 +
 clang/lib/Basic/Targets/SPIR.h                |  2 ++
 clang/lib/Basic/Targets/SystemZ.h             |  1 +
 clang/lib/Basic/Targets/TCE.h                 |  1 +
 clang/lib/Basic/Targets/WebAssembly.h         |  1 +
 clang/lib/Basic/Targets/X86.h                 |  1 +
 clang/lib/CodeGen/CGHLSLRuntime.cpp           |  2 ++
 clang/lib/CodeGen/CodeGenModule.cpp           | 11 ++++++++
 clang/lib/Sema/SemaDeclAttr.cpp               |  3 +++
 clang/lib/Sema/SemaHLSL.cpp                   | 22 +++++++++++++++
 clang/test/CodeGenHLSL/vk-output-builtin.hlsl | 15 +++++++++++
 .../test/SemaHLSL/vk-ext-output-builtin.hlsl  | 27 +++++++++++++++++++
 .../SemaTemplate/address_space-dependent.cpp  |  4 +--
 23 files changed, 137 insertions(+), 3 deletions(-)
 create mode 100644 clang/test/CodeGenHLSL/vk-output-builtin.hlsl
 create mode 100644 clang/test/SemaHLSL/vk-ext-output-builtin.hlsl

diff --git a/clang/include/clang/Basic/AddressSpaces.h b/clang/include/clang/Basic/AddressSpaces.h
index 7280b8fc923d2..a941805423bca 100644
--- a/clang/include/clang/Basic/AddressSpaces.h
+++ b/clang/include/clang/Basic/AddressSpaces.h
@@ -62,6 +62,7 @@ enum class LangAS : unsigned {
   hlsl_private,
   hlsl_device,
   hlsl_input,
+  hlsl_output,
   hlsl_push_constant,
 
   // Wasm specific address spaces.
diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td
index f697262d603bf..6d08ff6fecf5b 100644
--- a/clang/include/clang/Basic/Attr.td
+++ b/clang/include/clang/Basic/Attr.td
@@ -146,6 +146,12 @@ def HLSLInputBuiltin
                            S->getType().isConstQualified()}],
                     "static const globals">;
 
+def HLSLOutputBuiltin
+    : SubsetSubject<Var, [{S->hasGlobalStorage() &&
+                           S->getStorageClass() == StorageClass::SC_Static &&
+                           !S->getType().isConstQualified()}],
+                    "static globals">;
+
 def GlobalVar : SubsetSubject<Var,
                              [{S->hasGlobalStorage()}], "global variables">;
 
@@ -5217,6 +5223,14 @@ def HLSLVkExtBuiltinInput : InheritableAttr {
   let Documentation = [HLSLVkExtBuiltinInputDocs];
 }
 
+def HLSLVkExtBuiltinOutput : InheritableAttr {
+  let Spellings = [CXX11<"vk", "ext_builtin_output">];
+  let Args = [UnsignedArgument<"BuiltIn">];
+  let Subjects = SubjectList<[HLSLOutputBuiltin], ErrorDiag>;
+  let LangOpts = [HLSL];
+  let Documentation = [HLSLVkExtBuiltinOutputDocs];
+}
+
 def HLSLVkPushConstant : InheritableAttr {
   let Spellings = [CXX11<"vk", "push_constant">];
   let Args = [];
diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td
index 555a54fd51a89..d93dcf5e9b2fd 100644
--- a/clang/include/clang/Basic/AttrDocs.td
+++ b/clang/include/clang/Basic/AttrDocs.td
@@ -8978,6 +8978,29 @@ https://github.com/microsoft/hlsl-specs/blob/main/proposals/0011-inline-spirv.md
   }];
 }
 
+def HLSLVkExtBuiltinOutputDocs : Documentation {
+  let Category = DocCatVariable;
+  let Content = [{
+Vulkan shaders have `Output` builtins. Those variables are externally
+visible to the driver/pipeline, but each copy is private to the current
+lane.
+
+Those builtins can be declared using the `[[vk::ext_builtin_output]]`
+attribute like follows:
+
+.. code-block:: c++
+
+  [[vk::ext_builtin_output(/* Position */ 0)]]
+  static float4 position;
+
+This variable will be lowered into a module-level variable, with the `Output`
+storage class, and the `BuiltIn 0` decoration.
+
+The full documentation for this inline SPIR-V attribute can be found here:
+https://github.com/microsoft/hlsl-specs/blob/main/proposals/0011-inline-spirv.md
+  }];
+}
+
 def HLSLVkPushConstantDocs : Documentation {
   let Category = DocCatVariable;
   let Content = [{
diff --git a/clang/include/clang/Sema/SemaHLSL.h b/clang/include/clang/Sema/SemaHLSL.h
index cf9b8c39b109e..6f62fbc635d9c 100644
--- a/clang/include/clang/Sema/SemaHLSL.h
+++ b/clang/include/clang/Sema/SemaHLSL.h
@@ -190,6 +190,7 @@ class SemaHLSL : public SemaBase {
   void handleSemanticAttr(Decl *D, const ParsedAttr &AL);
 
   void handleVkExtBuiltinInputAttr(Decl *D, const ParsedAttr &AL);
+  void handleVkExtBuiltinOutputAttr(Decl *D, const ParsedAttr &AL);
   void handleVkPushConstantAttr(Decl *D, const ParsedAttr &AL);
 
   bool CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall);
diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp
index a351bc34af798..78524c205eb3d 100644
--- a/clang/lib/AST/Type.cpp
+++ b/clang/lib/AST/Type.cpp
@@ -101,6 +101,7 @@ bool Qualifiers::isTargetAddressSpaceSupersetOf(LangAS A, LangAS B,
          (A == LangAS::Default && B == LangAS::hlsl_private) ||
          (A == LangAS::Default && B == LangAS::hlsl_device) ||
          (A == LangAS::Default && B == LangAS::hlsl_input) ||
+         (A == LangAS::Default && B == LangAS::hlsl_output) ||
          (A == LangAS::Default && B == LangAS::hlsl_push_constant) ||
          // Conversions from target specific address spaces may be legal
          // depending on the target information.
diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp
index 3375630827501..80f5b90ba35c4 100644
--- a/clang/lib/AST/TypePrinter.cpp
+++ b/clang/lib/AST/TypePrinter.cpp
@@ -2707,6 +2707,8 @@ std::string Qualifiers::getAddrSpaceAsString(LangAS AS) {
     return "hlsl_device";
   case LangAS::hlsl_input:
     return "hlsl_input";
+  case LangAS::hlsl_output:
+    return "hlsl_output";
   case LangAS::hlsl_push_constant:
     return "hlsl_push_constant";
   case LangAS::wasm_funcref:
diff --git a/clang/lib/Basic/TargetInfo.cpp b/clang/lib/Basic/TargetInfo.cpp
index 38edc65801384..e6ae89e0948c5 100644
--- a/clang/lib/Basic/TargetInfo.cpp
+++ b/clang/lib/Basic/TargetInfo.cpp
@@ -52,7 +52,8 @@ static const LangASMap FakeAddrSpaceMap = {
     15, // hlsl_private
     16, // hlsl_device
     17, // hlsl_input
-    18, // hlsl_push_constant
+    18, // hlsl_output
+    19, // hlsl_push_constant
     20, // wasm_funcref
 };
 
diff --git a/clang/lib/Basic/Targets/AArch64.h b/clang/lib/Basic/Targets/AArch64.h
index f9dffed8769ef..0a29bad81939b 100644
--- a/clang/lib/Basic/Targets/AArch64.h
+++ b/clang/lib/Basic/Targets/AArch64.h
@@ -49,6 +49,7 @@ static const unsigned ARM64AddrSpaceMap[] = {
     0, // hlsl_private
     0, // hlsl_device
     0, // hlsl_input
+    0, // hlsl_output
     0, // hlsl_push_constant
     // Wasm address space values for this target are dummy values,
     // as it is only enabled for Wasm targets.
diff --git a/clang/lib/Basic/Targets/AMDGPU.cpp b/clang/lib/Basic/Targets/AMDGPU.cpp
index c9cd01080fd0c..2c05b3c6512fb 100644
--- a/clang/lib/Basic/Targets/AMDGPU.cpp
+++ b/clang/lib/Basic/Targets/AMDGPU.cpp
@@ -53,6 +53,7 @@ const LangASMap AMDGPUTargetInfo::AMDGPUDefIsGenMap = {
     llvm::AMDGPUAS::PRIVATE_ADDRESS, // hlsl_private
     llvm::AMDGPUAS::GLOBAL_ADDRESS,  // hlsl_device
     llvm::AMDGPUAS::PRIVATE_ADDRESS, // hlsl_input
+    llvm::AMDGPUAS::PRIVATE_ADDRESS, // hlsl_output
     llvm::AMDGPUAS::GLOBAL_ADDRESS,  // hlsl_push_constant
 };
 
@@ -82,6 +83,7 @@ const LangASMap AMDGPUTargetInfo::AMDGPUDefIsPrivMap = {
     llvm::AMDGPUAS::PRIVATE_ADDRESS,  // hlsl_private
     llvm::AMDGPUAS::GLOBAL_ADDRESS,   // hlsl_device
     llvm::AMDGPUAS::PRIVATE_ADDRESS,  // hlsl_input
+    llvm::AMDGPUAS::PRIVATE_ADDRESS,  // hlsl_output
     llvm::AMDGPUAS::GLOBAL_ADDRESS,   // hlsl_push_constant
 };
 } // namespace targets
diff --git a/clang/lib/Basic/Targets/DirectX.h b/clang/lib/Basic/Targets/DirectX.h
index 3976238bede4a..8b21b86bac264 100644
--- a/clang/lib/Basic/Targets/DirectX.h
+++ b/clang/lib/Basic/Targets/DirectX.h
@@ -46,6 +46,7 @@ static const unsigned DirectXAddrSpaceMap[] = {
     0, // hlsl_private
     0, // hlsl_device
     0, // hlsl_input
+    0, // hlsl_output
     0, // hlsl_push_constant
     // Wasm address space values for this target are dummy values,
     // as it is only enabled for Wasm targets.
diff --git a/clang/lib/Basic/Targets/NVPTX.h b/clang/lib/Basic/Targets/NVPTX.h
index 2e142cc95f9bb..69ee20f38343b 100644
--- a/clang/lib/Basic/Targets/NVPTX.h
+++ b/clang/lib/Basic/Targets/NVPTX.h
@@ -50,6 +50,7 @@ static const unsigned NVPTXAddrSpaceMap[] = {
     0, // hlsl_private
     0, // hlsl_device
     0, // hlsl_input
+    0, // hlsl_output
     0, // hlsl_push_constant
     // Wasm address space values for this target are dummy values,
     // as it is only enabled for Wasm targets.
diff --git a/clang/lib/Basic/Targets/SPIR.h b/clang/lib/Basic/Targets/SPIR.h
index 11a45d17e4aa4..6f4154fcf311f 100644
--- a/clang/lib/Basic/Targets/SPIR.h
+++ b/clang/lib/Basic/Targets/SPIR.h
@@ -52,6 +52,7 @@ static const unsigned SPIRDefIsPrivMap[] = {
     10, // hlsl_private
     11, // hlsl_device
     7,  // hlsl_input
+    8,  // hlsl_output
     13, // hlsl_push_constant
     // Wasm address space values for this target are dummy values,
     // as it is only enabled for Wasm targets.
@@ -89,6 +90,7 @@ static const unsigned SPIRDefIsGenMap[] = {
     10, // hlsl_private
     11, // hlsl_device
     7,  // hlsl_input
+    8,  // hlsl_output
     13, // hlsl_push_constant
     // Wasm address space values for this target are dummy values,
     // as it is only enabled for Wasm targets.
diff --git a/clang/lib/Basic/Targets/SystemZ.h b/clang/lib/Basic/Targets/SystemZ.h
index 2bcf75deb0a91..00f7d7a055b24 100644
--- a/clang/lib/Basic/Targets/SystemZ.h
+++ b/clang/lib/Basic/Targets/SystemZ.h
@@ -46,6 +46,7 @@ static const unsigned ZOSAddressMap[] = {
     0, // hlsl_private
     0, // hlsl_device
     0, // hlsl_input
+    0, // hlsl_output
     0, // hlsl_push_constant
     0  // wasm_funcref
 };
diff --git a/clang/lib/Basic/Targets/TCE.h b/clang/lib/Basic/Targets/TCE.h
index 161025378c471..2b22f4c4ec724 100644
--- a/clang/lib/Basic/Targets/TCE.h
+++ b/clang/lib/Basic/Targets/TCE.h
@@ -55,6 +55,7 @@ static const unsigned TCEOpenCLAddrSpaceMap[] = {
     0, // hlsl_private
     0, // hlsl_device
     0, // hlsl_input
+    0, // hlsl_output
     0, // hlsl_push_constant
     // Wasm address space values for this target are dummy values,
     // as it is only enabled for Wasm targets.
diff --git a/clang/lib/Basic/Targets/WebAssembly.h b/clang/lib/Basic/Targets/WebAssembly.h
index 8128dd96068a0..808342485cad0 100644
--- a/clang/lib/Basic/Targets/WebAssembly.h
+++ b/clang/lib/Basic/Targets/WebAssembly.h
@@ -46,6 +46,7 @@ static const unsigned WebAssemblyAddrSpaceMap[] = {
     0,  // hlsl_private
     0,  // hlsl_device
     0,  // hlsl_input
+    0,  // hlsl_output
     0,  // hlsl_push_constant
     20, // wasm_funcref
 };
diff --git a/clang/lib/Basic/Targets/X86.h b/clang/lib/Basic/Targets/X86.h
index bd9127b2ec8b5..c7afcc7c86053 100644
--- a/clang/lib/Basic/Targets/X86.h
+++ b/clang/lib/Basic/Targets/X86.h
@@ -50,6 +50,7 @@ static const unsigned X86AddrSpaceMap[] = {
     0,   // hlsl_private
     0,   // hlsl_device
     0,   // hlsl_input
+    0,   // hlsl_output
     0,   // hlsl_push_constant
     // Wasm address space values for this target are dummy values,
     // as it is only enabled for Wasm targets.
diff --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp b/clang/lib/CodeGen/CGHLSLRuntime.cpp
index c8a0ab34ae848..4e6f853890c83 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.cpp
+++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp
@@ -1163,6 +1163,8 @@ void CGHLSLRuntime::handleGlobalVarDefinition(const VarDecl *VD,
                                               llvm::GlobalVariable *GV) {
   if (auto Attr = VD->getAttr<HLSLVkExtBuiltinInputAttr>())
     addSPIRVBuiltinDecoration(GV, Attr->getBuiltIn());
+  if (auto Attr = VD->getAttr<HLSLVkExtBuiltinOutputAttr>())
+    addSPIRVBuiltinDecoration(GV, Attr->getBuiltIn());
 }
 
 llvm::Instruction *CGHLSLRuntime::getConvergenceToken(BasicBlock &BB) {
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index daaa846bf42bc..2be7417e8b391 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -4439,6 +4439,17 @@ void CodeGenModule::EmitGlobal(GlobalDecl GD) {
           return;
         }
       }
+
+      // HLSL extern globals can be read/written to by the pipeline. Those
+      // are declared, but never defined.
+      if (LangOpts.HLSL) {
+        if (VD->getStorageClass() == SC_Extern) {
+          auto GV = cast<llvm::GlobalVariable>(GetAddrOfGlobalVar(VD));
+          getHLSLRuntime().handleGlobalVarDefinition(VD, GV);
+          return;
+        }
+      }
+
       // If this declaration may have caused an inline variable definition to
       // change linkage, make sure that it's emitted.
       if (Context.getInlineVariableDefinitionKind(VD) ==
diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index 3c1e00c206dc3..131559f2cf786 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -7953,6 +7953,9 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL,
   case ParsedAttr::AT_HLSLVkExtBuiltinInput:
     S.HLSL().handleVkExtBuiltinInputAttr(D, AL);
     break;
+  case ParsedAttr::AT_HLSLVkExtBuiltinOutput:
+    S.HLSL().handleVkExtBuiltinOutputAttr(D, AL);
+    break;
   case ParsedAttr::AT_HLSLVkPushConstant:
     S.HLSL().handleVkPushConstantAttr(D, AL);
     break;
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index 823d312df296e..19c1f5bbd86c7 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -1842,6 +1842,14 @@ void SemaHLSL::handleVkExtBuiltinInputAttr(Decl *D, const ParsedAttr &AL) {
                  HLSLVkExtBuiltinInputAttr(getASTContext(), AL, ID));
 }
 
+void SemaHLSL::handleVkExtBuiltinOutputAttr(Decl *D, const ParsedAttr &AL) {
+  uint32_t ID;
+  if (!SemaRef.checkUInt32Argument(AL, AL.getArgAsExpr(0), ID))
+    return;
+  D->addAttr(::new (getASTContext())
+                 HLSLVkExtBuiltinOutputAttr(getASTContext(), AL, ID));
+}
+
 void SemaHLSL::handleVkPushConstantAttr(Decl *D, const ParsedAttr &AL) {
   D->addAttr(::new (getASTContext())
                  HLSLVkPushConstantAttr(getASTContext(), AL));
@@ -4857,6 +4865,20 @@ void SemaHLSL::deduceAddressSpace(VarDecl *Decl) {
     return;
   }
 
+  if (Decl->hasAttr<HLSLVkExtBuiltinOutputAttr>()) {
+    LangAS ImplAS = LangAS::hlsl_output;
+    Type = SemaRef.getASTContext().getAddrSpaceQualType(Type, ImplAS);
+    Decl->setType(Type);
+
+    // HLSL uses `static` differently than C++. For BuiltIn output, the static
+    // does not imply private to the module scope.
+    // Marking it as external to reflect the semantic this attribute brings.
+    // See https://github.com/microsoft/hlsl-specs/issues/350
+    VarDecl *VD = cast<VarDecl>(Decl);
+    VD->setStorageClass(SC_Extern);
+    return;
+  }
+
   bool IsVulkan = getASTContext().getTargetInfo().getTriple().getOS() ==
                   llvm::Triple::Vulkan;
   if (IsVulkan && Decl->hasAttr<HLSLVkPushConstantAttr>()) {
diff --git a/clang/test/CodeGenHLSL/vk-output-builtin.hlsl b/clang/test/CodeGenHLSL/vk-output-builtin.hlsl
new file mode 100644
index 0000000000000..df521113476eb
--- /dev/null
+++ b/clang/test/CodeGenHLSL/vk-output-builtin.hlsl
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -finclude-default-header -x hlsl -triple \
+// RUN:   spirv-unknown-vulkan1.3-vertex %s -emit-llvm -O3 -o - | FileCheck %s
+
+[[vk::ext_builtin_output(/* Position */ 0)]]
+static float4 position;
+// CHECK: @position = external hidden local_unnamed_addr addrspace(8) global <4 x float>, align 16, !spirv.Decorations [[META0:![0-9]+]]
+
+RWStructuredBuffer<float4> input : register(u1, space0);
+
+void main() {
+  position = input[0];
+  // CHECK: store <4 x float> %[[#]], ptr addrspace(8) @position, align 16
+}
+// CHECK: [[META0]] = !{[[META1:![0-9]+]]}
+// CHECK: [[META1]] = !{i32 11, i32 0}
diff --git a/clang/test/SemaHLSL/vk-ext-output-builtin.hlsl b/clang/test/SemaHLSL/vk-ext-output-builtin.hlsl
new file mode 100644
index 0000000000000..c4bf85debaaeb
--- /dev/null
+++ b/clang/test/SemaHLSL/vk-ext-output-builtin.hlsl
@@ -0,0 +1,27 @@
+// RUN: %clang_cc1 -triple spirv-unkown-vulkan1.3-compute -x hlsl -hlsl-entry foo  -finclude-default-header -o - %s -verify
+
+// expected-error at +1 {{'vk::ext_builtin_output' attribute only applies to static globals}}
+[[vk::ext_builtin_output(/* Position */ 0)]]
+float4 position0;
+
+// expected-error at +1 {{'vk::ext_builtin_output' attribute only applies to static globals}}
+[[vk::ext_builtin_output(/* Position */ 0)]]
+// expected-error at +1 {{default initialization of an object of const type 'const hlsl_private float4' (aka 'const hlsl_private vector<float, 4>')}}
+static const float4 position1;
+
+// expected-error at +1 {{'vk::ext_builtin_output' attribute takes one argument}}
+[[vk::ext_builtin_output()]]
+static float4 position2;
+
+// expected-error at +1 {{'vk::ext_builtin_output' attribute requires an integer constant}}
+[[vk::ext_builtin_output(0.4f)]]
+static float4 position3;
+
+// expected-error at +1 {{'vk::ext_builtin_output' attribute only applies to static globals}}
+[[vk::ext_builtin_output(0)]]
+void some_function() {
+}
+
+[numthreads(1,1,1)]
+void foo() {
+}
diff --git a/clang/test/SemaTemplate/address_space-dependent.cpp b/clang/test/SemaTemplate/address_space-dependent.cpp
index cba21b416bb48..3fdccb2c71a76 100644
--- a/clang/test/SemaTemplate/address_space-dependent.cpp
+++ b/clang/test/SemaTemplate/address_space-dependent.cpp
@@ -43,7 +43,7 @@ void neg() {
 
 template <long int I>
 void tooBig() {
-  __attribute__((address_space(I))) int *bounds; // expected-error {{address space is larger than the maximum supported (8388581)}}
+  __attribute__((address_space(I))) int *bounds; // expected-error {{address space is larger than the maximum supported (8388580)}}
 }
 
 template <long int I>
@@ -101,7 +101,7 @@ int main() {
   car<1, 2, 3>(); // expected-note {{in instantiation of function template specialization 'car<1, 2, 3>' requested here}}
   HasASTemplateFields<1> HASTF;
   neg<-1>(); // expected-note {{in instantiation of function template specialization 'neg<-1>' requested here}}
-  correct<0x7FFFE5>();
+  correct<0x7FFFE4>();
   tooBig<8388650>(); // expected-note {{in instantiation of function template specialization 'tooBig<8388650L>' requested here}}
 
   __attribute__((address_space(1))) char *x;

>From f6ff1085340ae18cb70410f1262adfdc7b44f469 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nathan=20Gau=C3=ABr?= <github at keenuts.net>
Date: Wed, 25 Mar 2026 14:14:31 +0100
Subject: [PATCH 2/3] Update clang/test/SemaHLSL/vk-ext-output-builtin.hlsl

Co-authored-by: Steven Perron <stevenperron at google.com>
---
 clang/test/SemaHLSL/vk-ext-output-builtin.hlsl | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/test/SemaHLSL/vk-ext-output-builtin.hlsl b/clang/test/SemaHLSL/vk-ext-output-builtin.hlsl
index c4bf85debaaeb..75129c27f85d7 100644
--- a/clang/test/SemaHLSL/vk-ext-output-builtin.hlsl
+++ b/clang/test/SemaHLSL/vk-ext-output-builtin.hlsl
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple spirv-unkown-vulkan1.3-compute -x hlsl -hlsl-entry foo  -finclude-default-header -o - %s -verify
+// RUN: %clang_cc1 -triple spirv-unknown-vulkan1.3-compute -x hlsl -hlsl-entry foo  -finclude-default-header -o - %s -verify
 
 // expected-error at +1 {{'vk::ext_builtin_output' attribute only applies to static globals}}
 [[vk::ext_builtin_output(/* Position */ 0)]]

>From 8989063dda1cc4e9d0e8b556a9c802e1ca2a1ce1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nathan=20Gau=C3=ABr?= <brioche at google.com>
Date: Wed, 25 Mar 2026 14:16:41 +0100
Subject: [PATCH 3/3] pr-feedback: minor nits

---
 clang/include/clang/Basic/Attr.td | 2 +-
 clang/lib/Sema/SemaHLSL.cpp       | 1 -
 2 files changed, 1 insertion(+), 2 deletions(-)

diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td
index 6d08ff6fecf5b..5b0215f466e62 100644
--- a/clang/include/clang/Basic/Attr.td
+++ b/clang/include/clang/Basic/Attr.td
@@ -150,7 +150,7 @@ def HLSLOutputBuiltin
     : SubsetSubject<Var, [{S->hasGlobalStorage() &&
                            S->getStorageClass() == StorageClass::SC_Static &&
                            !S->getType().isConstQualified()}],
-                    "static globals">;
+                    "non-const static globals">;
 
 def GlobalVar : SubsetSubject<Var,
                              [{S->hasGlobalStorage()}], "global variables">;
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index 19c1f5bbd86c7..6c6a7577e0723 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -4874,7 +4874,6 @@ void SemaHLSL::deduceAddressSpace(VarDecl *Decl) {
     // does not imply private to the module scope.
     // Marking it as external to reflect the semantic this attribute brings.
     // See https://github.com/microsoft/hlsl-specs/issues/350
-    VarDecl *VD = cast<VarDecl>(Decl);
     VD->setStorageClass(SC_Extern);
     return;
   }



More information about the cfe-commits mailing list