[clang] [HLSL][SPIRV] Add vk::constant_id attribute. (PR #142638)

Steven Perron via cfe-commits cfe-commits at lists.llvm.org
Tue Jun 3 09:27:40 PDT 2025


https://github.com/s-perron created https://github.com/llvm/llvm-project/pull/142638

The vk::constant_id attribute is used to indicate that a global const variable
represents a specialization constant in SPIR-V. This PR adds this
attribute to clang.

The documetation for the attribute is [here](https://github.com/microsoft/DirectXShaderCompiler/blob/main/docs/SPIR-V.rst#specialization-constants).

Fixes #142448


>From 022bc4d031ea1655b82dc701fff315abd002ca15 Mon Sep 17 00:00:00 2001
From: Steven Perron <stevenperron at google.com>
Date: Fri, 30 May 2025 12:32:21 -0400
Subject: [PATCH] [HLSL][SPIRV] Add vk::constant_id attribute.

The vk::constant_id attribute is used to indicate that a global const variable
represents a specialization constant in SPIR-V. This PR adds this
attribute to clang.

The documetation for the attribute is [here](https://github.com/microsoft/DirectXShaderCompiler/blob/main/docs/SPIR-V.rst#specialization-constants).

Fixes #142448
---
 clang/include/clang/Basic/Attr.td             |  8 +++
 clang/include/clang/Basic/AttrDocs.td         | 15 +++++
 .../clang/Basic/DiagnosticSemaKinds.td        | 15 +++++
 clang/include/clang/Sema/SemaHLSL.h           |  3 +
 clang/lib/AST/ExprConstant.cpp                |  5 ++
 clang/lib/Basic/Attributes.cpp                |  3 +-
 clang/lib/CodeGen/CodeGenModule.cpp           | 23 +++++++
 clang/lib/Sema/SemaDecl.cpp                   | 18 ++++++
 clang/lib/Sema/SemaDeclAttr.cpp               |  3 +
 clang/lib/Sema/SemaHLSL.cpp                   | 61 ++++++++++++++++++-
 .../test/AST/HLSL/vk.spec-constnat.usage.hlsl | 12 ++++
 .../SpirvType.alignment.hlsl                  |  0
 .../SpirvType.hlsl                            |  0
 .../vk-features/vk.spec-constant.hlsl         | 44 +++++++++++++
 .../SemaHLSL/vk.spec-constant.error1.hlsl     | 39 ++++++++++++
 15 files changed, 247 insertions(+), 2 deletions(-)
 create mode 100644 clang/test/AST/HLSL/vk.spec-constnat.usage.hlsl
 rename clang/test/CodeGenHLSL/{inline-spirv => vk-features}/SpirvType.alignment.hlsl (100%)
 rename clang/test/CodeGenHLSL/{inline-spirv => vk-features}/SpirvType.hlsl (100%)
 create mode 100644 clang/test/CodeGenHLSL/vk-features/vk.spec-constant.hlsl
 create mode 100644 clang/test/SemaHLSL/vk.spec-constant.error1.hlsl

diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td
index db02449a3dd12..51d1ddf80c65f 100644
--- a/clang/include/clang/Basic/Attr.td
+++ b/clang/include/clang/Basic/Attr.td
@@ -4949,6 +4949,14 @@ def HLSLWaveSize: InheritableAttr {
   let Documentation = [WaveSizeDocs];
 }
 
+def HLSLVkConstantId : InheritableAttr {
+  let Spellings = [CXX11<"vk", "constant_id">];
+  let Args = [IntArgument<"Id">];
+  let Subjects = SubjectList<[Var]>;
+  let LangOpts = [HLSL];
+  let Documentation = [VkConstantIdDocs];
+}
+
 def RandomizeLayout : InheritableAttr {
   let Spellings = [GCC<"randomize_layout">];
   let Subjects = SubjectList<[Record]>;
diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td
index 65d66dd398ad1..8ddf109b733c1 100644
--- a/clang/include/clang/Basic/AttrDocs.td
+++ b/clang/include/clang/Basic/AttrDocs.td
@@ -8195,6 +8195,21 @@ and https://microsoft.github.io/hlsl-specs/proposals/0013-wave-size-range.html
   }];
 }
 
+def VkConstantIdDocs : Documentation {
+  let Category = DocCatFunction;
+  let Content = [{
+The ``vk::constant_id`` attribute specify the id for a SPIR-V specialization
+constant. The attribute applies to const global scalar variables. The variable must be initialized with a C++11 constexpr.
+In SPIR-V, the
+variable will be replaced with an `OpSpecConstant` with the given id.
+The syntax is:
+
+.. code-block:: text
+
+  ``[[vk::constant_id(<Id>)]] const T Name = <Init>``
+}];
+}
+
 def RootSignatureDocs : Documentation {
   let Category = DocCatFunction;
   let Content = [{
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index efc842bb4c42e..9214775246a15 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -12888,6 +12888,21 @@ def err_spirv_enum_not_int : Error<
 def err_spirv_enum_not_valid : Error<
    "invalid value for %select{storage class}0 argument">;
 
+def err_specialization_const_lit_init
+    : Error<"variable with 'vk::constant_id' attribute cannot have an "
+            "initializer that is not a constexpr">;
+def err_specialization_const_is_not_externally_visible
+    : Error<"variable with 'vk::constant_id' attribute must be externally "
+            "visible">;
+def err_specialization_const_missing_initializer
+    : Error<
+          "variable with 'vk::constant_id' attribute must have an initializer">;
+def err_specialization_const_missing_const
+    : Error<"variable with 'vk::constant_id' attribute must be const">;
+def err_specialization_const_is_not_int_or_float
+    : Error<"variable with 'vk::constant_id' attribute must be an enum, bool, "
+            "integer, or floating point value">;
+
 // errors of expect.with.probability
 def err_probability_not_constant_float : Error<
    "probability argument to __builtin_expect_with_probability must be constant "
diff --git a/clang/include/clang/Sema/SemaHLSL.h b/clang/include/clang/Sema/SemaHLSL.h
index 15182bb27bbdf..d9442f552c73f 100644
--- a/clang/include/clang/Sema/SemaHLSL.h
+++ b/clang/include/clang/Sema/SemaHLSL.h
@@ -98,6 +98,8 @@ class SemaHLSL : public SemaBase {
   HLSLWaveSizeAttr *mergeWaveSizeAttr(Decl *D, const AttributeCommonInfo &AL,
                                       int Min, int Max, int Preferred,
                                       int SpelledArgsCount);
+  HLSLVkConstantIdAttr *
+  mergeVkConstantIdAttr(Decl *D, const AttributeCommonInfo &AL, int Id);
   HLSLShaderAttr *mergeShaderAttr(Decl *D, const AttributeCommonInfo &AL,
                                   llvm::Triple::EnvironmentType ShaderType);
   HLSLParamModifierAttr *
@@ -122,6 +124,7 @@ class SemaHLSL : public SemaBase {
   void handleRootSignatureAttr(Decl *D, const ParsedAttr &AL);
   void handleNumThreadsAttr(Decl *D, const ParsedAttr &AL);
   void handleWaveSizeAttr(Decl *D, const ParsedAttr &AL);
+  void handleVkConstantIdAttr(Decl *D, const ParsedAttr &AL);
   void handleSV_DispatchThreadIDAttr(Decl *D, const ParsedAttr &AL);
   void handleSV_GroupThreadIDAttr(Decl *D, const ParsedAttr &AL);
   void handleSV_GroupIDAttr(Decl *D, const ParsedAttr &AL);
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index b20e2690d0eee..f4b32f297bfcc 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -3570,6 +3570,11 @@ static bool evaluateVarDeclInit(EvalInfo &Info, const Expr *E,
   if (E->isValueDependent())
     return false;
 
+  // The initializer on a specialization constant is only its default value
+  // when it is not externally initialized. This value cannot be evaluated.
+  if (VD->hasAttr<HLSLVkConstantIdAttr>())
+    return false;
+
   // Dig out the initializer, and use the declaration which it's attached to.
   // FIXME: We should eventually check whether the variable has a reachable
   // initializing declaration.
diff --git a/clang/lib/Basic/Attributes.cpp b/clang/lib/Basic/Attributes.cpp
index ebc86a5adf7a7..241fdf644c5ba 100644
--- a/clang/lib/Basic/Attributes.cpp
+++ b/clang/lib/Basic/Attributes.cpp
@@ -213,7 +213,8 @@ getScopeFromNormalizedScopeName(StringRef ScopeName) {
       .Case("hlsl", AttributeCommonInfo::Scope::HLSL)
       .Case("msvc", AttributeCommonInfo::Scope::MSVC)
       .Case("omp", AttributeCommonInfo::Scope::OMP)
-      .Case("riscv", AttributeCommonInfo::Scope::RISCV);
+      .Case("riscv", AttributeCommonInfo::Scope::RISCV)
+      .Case("vk", AttributeCommonInfo::Scope::HLSL);
 }
 
 unsigned AttributeCommonInfo::calculateAttributeSpellingListIndex() const {
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index 6d2c705338ecf..20f85bbf3fc0e 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -5191,6 +5191,29 @@ CodeGenModule::GetOrCreateLLVMGlobal(StringRef MangledName, llvm::Type *Ty,
     if (const auto *CMA = D->getAttr<CodeModelAttr>())
       GV->setCodeModel(CMA->getModel());
 
+    if (const auto *ConstIdAttr = D->getAttr<HLSLVkConstantIdAttr>()) {
+      const Expr *Init = D->getInit();
+      APValue InitValue;
+      bool IsConstExpr = Init->isCXX11ConstantExpr(getContext(), &InitValue);
+      assert(IsConstExpr &&
+             "HLSLVkConstantIdAttr requires a constant initializer");
+      llvm::SmallString<10> InitString;
+      switch (InitValue.getKind()) {
+      case APValue::ValueKind::Int:
+        InitValue.getInt().toString(InitString);
+        break;
+      case APValue::ValueKind::Float:
+        InitValue.getFloat().toString(InitString);
+        break;
+      default:
+        llvm_unreachable(
+            "HLSLVkConstantIdAttr requires an int or float initializer");
+      }
+      std::string ConstIdStr =
+          (llvm::Twine(ConstIdAttr->getId()) + "," + InitString).str();
+      GV->addAttribute("spirv-constant-id", ConstIdStr);
+    }
+
     // Check if we a have a const declaration with an initializer, we may be
     // able to emit it as available_externally to expose it's value to the
     // optimizer.
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 86b871396ec90..89185ef11f256 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -2889,6 +2889,8 @@ static bool mergeDeclAttribute(Sema &S, NamedDecl *D,
     NewAttr = S.HLSL().mergeWaveSizeAttr(D, *WS, WS->getMin(), WS->getMax(),
                                          WS->getPreferred(),
                                          WS->getSpelledArgsCount());
+  else if (const auto *CI = dyn_cast<HLSLVkConstantIdAttr>(Attr))
+    NewAttr = S.HLSL().mergeVkConstantIdAttr(D, *CI, CI->getId());
   else if (const auto *SA = dyn_cast<HLSLShaderAttr>(Attr))
     NewAttr = S.HLSL().mergeShaderAttr(D, *SA, SA->getType());
   else if (isa<SuppressAttr>(Attr))
@@ -13757,6 +13759,14 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) {
     return;
   }
 
+  if (VDecl->hasAttr<HLSLVkConstantIdAttr>()) {
+    if (!Init->isCXX11ConstantExpr(Context)) {
+      Diag(VDecl->getLocation(), diag::err_specialization_const_lit_init);
+      VDecl->setInvalidDecl();
+      return;
+    }
+  }
+
   // Get the decls type and save a reference for later, since
   // CheckInitializerTypes may change it.
   QualType DclT = VDecl->getType(), SavT = DclT;
@@ -14217,6 +14227,14 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl) {
       }
     }
 
+    // HLSL variable with the `vk::constant_id` attribute must be initialized.
+    if (!Var->isInvalidDecl() && Var->hasAttr<HLSLVkConstantIdAttr>()) {
+      Diag(Var->getLocation(),
+           diag::err_specialization_const_missing_initializer);
+      Var->setInvalidDecl();
+      return;
+    }
+
     if (!Var->isInvalidDecl() && RealDecl->hasAttr<LoaderUninitializedAttr>()) {
       if (Var->getStorageClass() == SC_Extern) {
         Diag(Var->getLocation(), diag::err_loader_uninitialized_extern_decl)
diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index 119ba8486b09f..af617c04dd0d3 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -7505,6 +7505,9 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL,
   case ParsedAttr::AT_HLSLWaveSize:
     S.HLSL().handleWaveSizeAttr(D, AL);
     break;
+  case ParsedAttr::AT_HLSLVkConstantId:
+    S.HLSL().handleVkConstantIdAttr(D, AL);
+    break;
   case ParsedAttr::AT_HLSLSV_GroupThreadID:
     S.HLSL().handleSV_GroupThreadIDAttr(D, AL);
     break;
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index 43db85594de3d..a39787fb27d5d 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -505,6 +505,7 @@ static CXXRecordDecl *createHostLayoutStruct(Sema &S,
 // - empty structs
 // - zero-sized arrays
 // - non-variable declarations
+// - SPIR-V specialization constants
 // The layout struct will be added to the HLSLBufferDecl declarations.
 void createHostLayoutStructForBuffer(Sema &S, HLSLBufferDecl *BufDecl) {
   ASTContext &AST = S.getASTContext();
@@ -520,7 +521,8 @@ void createHostLayoutStructForBuffer(Sema &S, HLSLBufferDecl *BufDecl) {
   for (Decl *D : BufDecl->buffer_decls()) {
     VarDecl *VD = dyn_cast<VarDecl>(D);
     if (!VD || VD->getStorageClass() == SC_Static ||
-        VD->getType().getAddressSpace() == LangAS::hlsl_groupshared)
+        VD->getType().getAddressSpace() == LangAS::hlsl_groupshared ||
+        VD->hasAttr<HLSLVkConstantIdAttr>())
       continue;
     const Type *Ty = VD->getType()->getUnqualifiedDesugaredType();
     if (FieldDecl *FD =
@@ -607,6 +609,54 @@ HLSLWaveSizeAttr *SemaHLSL::mergeWaveSizeAttr(Decl *D,
   return Result;
 }
 
+HLSLVkConstantIdAttr *
+SemaHLSL::mergeVkConstantIdAttr(Decl *D, const AttributeCommonInfo &AL,
+                                int Id) {
+
+  auto &TargetInfo = getASTContext().getTargetInfo();
+  if (TargetInfo.getTriple().getArch() != llvm::Triple::spirv) {
+    Diag(AL.getLoc(), diag::warn_attribute_ignored) << AL;
+    return nullptr;
+  }
+
+  auto *VD = cast<VarDecl>(D);
+
+  if (!VD->getType()->isIntegerType() && !VD->getType()->isFloatingType()) {
+    Diag(VD->getLocation(), diag::err_specialization_const_is_not_int_or_float);
+    return nullptr;
+  }
+
+  if (VD->getStorageClass() != StorageClass::SC_None &&
+      VD->getStorageClass() != StorageClass::SC_Extern) {
+    Diag(VD->getLocation(),
+         diag::err_specialization_const_is_not_externally_visible);
+    return nullptr;
+  }
+
+  if (VD->isLocalVarDecl()) {
+    Diag(VD->getLocation(),
+         diag::err_specialization_const_is_not_externally_visible);
+    return nullptr;
+  }
+
+  if (!VD->getType().isConstQualified()) {
+    Diag(VD->getLocation(), diag::err_specialization_const_missing_const);
+    return nullptr;
+  }
+
+  if (HLSLVkConstantIdAttr *CI = D->getAttr<HLSLVkConstantIdAttr>()) {
+    if (CI->getId() != Id) {
+      Diag(CI->getLocation(), diag::err_hlsl_attribute_param_mismatch) << AL;
+      Diag(AL.getLoc(), diag::note_conflicting_attribute);
+    }
+    return nullptr;
+  }
+
+  HLSLVkConstantIdAttr *Result =
+      ::new (getASTContext()) HLSLVkConstantIdAttr(getASTContext(), AL, Id);
+  return Result;
+}
+
 HLSLShaderAttr *
 SemaHLSL::mergeShaderAttr(Decl *D, const AttributeCommonInfo &AL,
                           llvm::Triple::EnvironmentType ShaderType) {
@@ -1117,6 +1167,15 @@ void SemaHLSL::handleWaveSizeAttr(Decl *D, const ParsedAttr &AL) {
     D->addAttr(NewAttr);
 }
 
+void SemaHLSL::handleVkConstantIdAttr(Decl *D, const ParsedAttr &AL) {
+  uint32_t Id;
+  if (!SemaRef.checkUInt32Argument(AL, AL.getArgAsExpr(0), Id))
+    return;
+  HLSLVkConstantIdAttr *NewAttr = mergeVkConstantIdAttr(D, AL, Id);
+  if (NewAttr)
+    D->addAttr(NewAttr);
+}
+
 bool SemaHLSL::diagnoseInputIDType(QualType T, const ParsedAttr &AL) {
   const auto *VT = T->getAs<VectorType>();
 
diff --git a/clang/test/AST/HLSL/vk.spec-constnat.usage.hlsl b/clang/test/AST/HLSL/vk.spec-constnat.usage.hlsl
new file mode 100644
index 0000000000000..2383e3ad2a1cd
--- /dev/null
+++ b/clang/test/AST/HLSL/vk.spec-constnat.usage.hlsl
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -finclude-default-header -triple spirv-unknown-vulkan-compute -x hlsl -ast-dump -o - %s | FileCheck %s
+
+// CHECK: VarDecl {{.*}} specConst 'const hlsl_constant int' cinit
+// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 12
+// CHECK-NEXT: HLSLVkConstantIdAttr {{.*}} 10    
+[[vk::constant_id(10)]]
+const int specConst = 12;
+
+// CHECK: CXXRecordDecl {{.*}} implicit struct __cblayout_$Globals definition
+// CHECK-NOT: FieldDecl {{.*}} specConst 'int'
+
+
diff --git a/clang/test/CodeGenHLSL/inline-spirv/SpirvType.alignment.hlsl b/clang/test/CodeGenHLSL/vk-features/SpirvType.alignment.hlsl
similarity index 100%
rename from clang/test/CodeGenHLSL/inline-spirv/SpirvType.alignment.hlsl
rename to clang/test/CodeGenHLSL/vk-features/SpirvType.alignment.hlsl
diff --git a/clang/test/CodeGenHLSL/inline-spirv/SpirvType.hlsl b/clang/test/CodeGenHLSL/vk-features/SpirvType.hlsl
similarity index 100%
rename from clang/test/CodeGenHLSL/inline-spirv/SpirvType.hlsl
rename to clang/test/CodeGenHLSL/vk-features/SpirvType.hlsl
diff --git a/clang/test/CodeGenHLSL/vk-features/vk.spec-constant.hlsl b/clang/test/CodeGenHLSL/vk-features/vk.spec-constant.hlsl
new file mode 100644
index 0000000000000..5f2b0767bcf9b
--- /dev/null
+++ b/clang/test/CodeGenHLSL/vk-features/vk.spec-constant.hlsl
@@ -0,0 +1,44 @@
+// RUN: %clang_cc1 -finclude-default-header -x hlsl -triple \
+// RUN:   spirv-unknown-vulkan-compute %s -emit-llvm -disable-llvm-passes \
+// RUN:   -o - | FileCheck %s
+
+
+// CHECK-DAG: @_ZL3sc0 = external addrspace(12) constant i32, align 4 [[A0:#[0-9]+]]
+// CHECK-DAG: attributes [[A0]] = { "spirv-constant-id"="0,1" }                                                                                                                                                                                                                                                
+[[vk::constant_id(0)]]
+const bool sc0 = true;
+
+// CHECK-DAG: @_ZL3sc1 = external addrspace(12) constant i32, align 4 [[A1:#[0-9]+]]
+// CHECK-DAG: attributes [[A1]] = { "spirv-constant-id"="1,10" }                                                                                                                                                                                                                                               
+[[vk::constant_id(1)]]
+const int sc1 = 10;
+
+// CHECK-DAG: @_ZL3sc2 = external addrspace(12) constant i32, align 4 [[A2:#[0-9]+]]
+// CHECK-DAG: attributes [[A2]] = { "spirv-constant-id"="2,-20" }                                                                                                                                                                                                                                              
+[[vk::constant_id(2)]]
+const int sc2 = 10-30;
+
+// CHECK-DAG: @_ZL3sc3 = external addrspace(12) constant float, align 4 [[A3:#[0-9]+]]
+// CHECK-DAG: attributes [[A3]] = { "spirv-constant-id"="3,0.25" }
+[[vk::constant_id(3)]]
+const float sc3 = 0.5*0.5;
+
+// CHECK-DAG: @_ZL3sc4 = external addrspace(12) constant i32, align 4 [[A4:#[0-9]+]]
+// CHECK-DAG: attributes [[A4]] = { "spirv-constant-id"="4,2" }
+enum E {
+    A,
+    B,
+    C
+};
+
+[[vk::constant_id(4)]]
+const E sc4 = E::C;
+
+[numthreads(1,1,1)]
+void main() {
+    bool b = sc0;
+    int i = sc1;
+    int j = sc2;
+    float f = sc3;
+    E e = sc4;
+}
diff --git a/clang/test/SemaHLSL/vk.spec-constant.error1.hlsl b/clang/test/SemaHLSL/vk.spec-constant.error1.hlsl
new file mode 100644
index 0000000000000..2b6ac85ebc3ca
--- /dev/null
+++ b/clang/test/SemaHLSL/vk.spec-constant.error1.hlsl
@@ -0,0 +1,39 @@
+// RUN: %clang_cc1 -finclude-default-header -triple spirv-pc-vulkan1.3-compute -verify %s
+// RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.8-compute -verify %s
+
+#ifndef __spirv__
+// expected-warning at +2{{'constant_id' attribute ignored}}
+#endif
+[[vk::constant_id(0)]]
+const bool sc0 = true;
+
+#ifdef __spirv__
+[[vk::constant_id(1)]]
+// expected-error at +1{{variable with 'vk::constant_id' attribute cannot have an initializer that is not a constexpr}}
+const bool sc1 = sc0; // error
+
+[[vk::constant_id(2)]]
+// expected-error at +1{{variable with 'vk::constant_id' attribute must be externally visible}}
+static const bool sc2 = false; // error
+
+[[vk::constant_id(3)]]
+// expected-error at +1{{variable with 'vk::constant_id' attribute must have an initializer}}
+const bool sc3; // error
+
+[[vk::constant_id(4)]]
+// expected-error at +1{{variable with 'vk::constant_id' attribute must be const}}
+bool sc4 = false; // error
+
+[[vk::constant_id(5)]]
+// expected-error at +1{{variable with 'vk::constant_id' attribute must be an enum, bool, integer, or floating point value}}
+const int2 sc5 = {0,0}; // error
+#endif
+
+[numthreads(1,1,1)]
+void main() {
+  #ifdef __spirv__
+  [[vk::constant_id(6)]]
+  // expected-error at +1{{variable with 'vk::constant_id' attribute must be externally visible}}
+  const bool sc6 = false; // error
+  #endif
+}



More information about the cfe-commits mailing list