diff --git a/source/slang/slang-check-decl.cpp b/source/slang/slang-check-decl.cpp index 584b1f08172..9c652f191da 100644 --- a/source/slang/slang-check-decl.cpp +++ b/source/slang/slang-check-decl.cpp @@ -212,22 +212,42 @@ struct SemanticsDeclModifiersVisitor : public SemanticsDeclVisitorBase, // Export'd/Extern'd variables must be `const`, otherwise we may have a mismatch // causing errors. bool hasConst = false; + bool hasUniform = false; bool hasExportOrExtern = false; bool hasStatic = false; + bool hasSpecializationConstant = false; for (auto m : decl->modifiers) { if (as(m) || as(m)) hasExportOrExtern = true; else if (as(m)) hasConst = true; + else if (as(m)) + hasUniform = true; else if (as(m)) hasStatic = true; + else if (as(m) || as(m)) + hasSpecializationConstant = true; } if (hasExportOrExtern && hasConst != hasStatic) getSink()->diagnose( decl, Diagnostics::ExternAndExportVarDeclMustBeConst, decl->getName()); + + + // Global const or uniform variables with initializers must be static + // In HLSL, const global variables without static are uniform parameters + // that cannot have default values + // Exception: specialization constants are allowed to have initializers + if (isGlobalDecl(decl) && (hasConst || hasUniform) && !hasStatic && + !hasSpecializationConstant && decl->initExpr) + { + getSink()->diagnose( + decl, + Diagnostics::constGlobalVarWithInitRequiresStatic, + decl->getName()); + } } void visitDecl(Decl* decl) { checkModifiers(decl); } diff --git a/source/slang/slang-diagnostic-defs.h b/source/slang/slang-diagnostic-defs.h index 8dbdaaaa692..8716fb9d603 100644 --- a/source/slang/slang-diagnostic-defs.h +++ b/source/slang/slang-diagnostic-defs.h @@ -1502,6 +1502,12 @@ DIAGNOSTIC( ExternAndExportVarDeclMustBeConst, "extern and export variables must be static const: '$0'") +DIAGNOSTIC( + 31224, + Error, + constGlobalVarWithInitRequiresStatic, + "global const variable with initializer must be declared static: '$0'") + // Enums DIAGNOSTIC(32000, Error, invalidEnumTagType, "invalid tag type for 'enum': '$0'") diff --git a/tests/diagnostics/global-const-uniform-with-init.slang b/tests/diagnostics/global-const-uniform-with-init.slang new file mode 100644 index 00000000000..352c309e380 --- /dev/null +++ b/tests/diagnostics/global-const-uniform-with-init.slang @@ -0,0 +1,49 @@ +//TEST:SIMPLE(filecheck=CHK): -target hlsl -entry main + +// Test for diagnostic 31224: global const/uniform variables with initializers must be static +// Exception: specialization constants are allowed to have initializers without static +// Test for diagnostic 31219: specialization constants cannot be declared static + +// These should trigger error 31224 +//CHK-DAG: ([[# @LINE + 1]]): error 31224: global const variable with initializer must be declared static: 'globalConstWithInit' +const float globalConstWithInit = 1.0f; + +//CHK-DAG: ([[# @LINE + 1]]): error 31224: global const variable with initializer must be declared static: 'uniformWithInit' +uniform float uniformWithInit = 2.0f; + +// These are valid and should not produce errors +static const float staticConstWithInit = 3.0f; // OK - static const with init +const float globalConstNoInit; // OK - const without init +uniform float uniformNoInit; // OK - uniform without init + +// Specialization constants with initializers are allowed without static +[SpecializationConstant] +const int specConstInt = 42; // OK - specialization constant with init + +[vk::constant_id(5)] +const float specConstFloat = 3.14f; // OK - vk constant id with init + +// These should trigger error 31219: static specialization constants are not allowed +//CHK-DAG: ([[# @LINE + 2]]): error 31219: push or specialization constants cannot be 'static'. +[SpecializationConstant] +static const int staticSpecConstInt = 100; + +//CHK-DAG: ([[# @LINE + 2]]): error 31219: push or specialization constants cannot be 'static'. +[vk::constant_id(7)] +static const float staticSpecConstFloat = 2.71f; + +void functionScope() +{ + const float localConstWithInit = 4.0f; // OK - local const with init +} + +struct MyStruct +{ + static const float memberStaticConst = 5.0f; // OK - member static const +}; + +[shader("vertex")] +float4 main() : SV_Position +{ + return float4(staticConstWithInit, 0, 0, 1); +} \ No newline at end of file diff --git a/tests/diagnostics/global-uniform.slang b/tests/diagnostics/global-uniform.slang index de453711518..1223f624c0b 100644 --- a/tests/diagnostics/global-uniform.slang +++ b/tests/diagnostics/global-uniform.slang @@ -7,7 +7,7 @@ uniform float a; -const uint4 b = uint4(0,1,2,3); +static const uint4 b = uint4(0,1,2,3); struct C { float x; int y; }; C c; diff --git a/tests/diagnostics/global-uniform.slang.expected b/tests/diagnostics/global-uniform.slang.expected index 70877f4bd9e..3c9f3ba2a01 100644 --- a/tests/diagnostics/global-uniform.slang.expected +++ b/tests/diagnostics/global-uniform.slang.expected @@ -1,8 +1,5 @@ result code = 0 standard error = { -tests/diagnostics/global-uniform.slang(10): warning 39019: 'b' is implicitly a global shader parameter, not a global variable. If a global variable is intended, add the 'static' modifier. If a uniform shader parameter is intended, add the 'uniform' modifier to silence this warning. -const uint4 b = uint4(0,1,2,3); - ^ tests/diagnostics/global-uniform.slang(13): warning 39019: 'c' is implicitly a global shader parameter, not a global variable. If a global variable is intended, add the 'static' modifier. If a uniform shader parameter is intended, add the 'uniform' modifier to silence this warning. C c; ^