diff --git a/source/slang/slang-check-decl.cpp b/source/slang/slang-check-decl.cpp index e94a3eb10e..584ad10e6c 100644 --- a/source/slang/slang-check-decl.cpp +++ b/source/slang/slang-check-decl.cpp @@ -90,6 +90,10 @@ struct SemanticsDeclAttributesVisitor : public SemanticsDeclVisitorBase, void checkPrimalSubstituteOfAttribute( FunctionDeclBase* funcDecl, PrimalSubstituteOfAttribute* attr); + + void checkVarDeclCommon(VarDeclBase* varDecl); + + void visitVarDecl(VarDecl* varDecl) { checkVarDeclCommon(varDecl); } }; struct SemanticsDeclHeaderVisitor : public SemanticsDeclVisitorBase, @@ -11712,6 +11716,41 @@ bool tryCheckDerivativeOfAttributeImpl( return tempSink.getErrorCount() == 0; } +void SemanticsDeclAttributesVisitor::checkVarDeclCommon(VarDeclBase* varDecl) +{ + bool hasSpecConstAttr = false; + bool hasPushConstAttr = false; + for (auto modifier : varDecl->modifiers) + { + if (as(modifier) || as(modifier)) + { + // Specialization constant. + // Check that type is basic type. + if (!as(varDecl->getType()) && + !as(varDecl->getType())) + { + getSink()->diagnose(modifier, Diagnostics::specializationConstantMustBeScalar); + } + hasSpecConstAttr = true; + } + else if (as(modifier)) + { + hasPushConstAttr = true; + } + } + if (hasSpecConstAttr && hasPushConstAttr) + { + getSink()->diagnose(varDecl, Diagnostics::variableCannotBePushAndSpecializationConstant, varDecl->getName()); + } + if (hasSpecConstAttr || hasPushConstAttr) + { + if (varDecl->findModifier()) + { + getSink()->diagnose(varDecl, Diagnostics::pushOrSpecializationConstantCannotBeStatic); + } + } +} + void SemanticsDeclAttributesVisitor::checkForwardDerivativeOfAttribute( FunctionDeclBase* funcDecl, ForwardDerivativeOfAttribute* attr) diff --git a/source/slang/slang-diagnostic-defs.h b/source/slang/slang-diagnostic-defs.h index d6409e42e7..305013f431 100644 --- a/source/slang/slang-diagnostic-defs.h +++ b/source/slang/slang-diagnostic-defs.h @@ -1213,8 +1213,21 @@ DIAGNOSTIC( Error, unrecognizedGLSLLayoutQualifierOrRequiresAssignment, "GLSL layout qualifier is unrecognized or requires assignment") - - +DIAGNOSTIC( + 31218, + Error, + specializationConstantMustBeScalar, + "specialization constant must be a scalar.") +DIAGNOSTIC( + 31219, + Error, + pushOrSpecializationConstantCannotBeStatic, + "push or specialization constants cannot be 'static'.") +DIAGNOSTIC( + 31220, + Error, + variableCannotBePushAndSpecializationConstant, + "'$0' cannot be a push constant and a specialization constant at the same time") // Enums DIAGNOSTIC(32000, Error, invalidEnumTagType, "invalid tag type for 'enum': '$0'") diff --git a/source/slang/slang-parameter-binding.cpp b/source/slang/slang-parameter-binding.cpp index c232d0aee0..7fb719053f 100644 --- a/source/slang/slang-parameter-binding.cpp +++ b/source/slang/slang-parameter-binding.cpp @@ -3858,7 +3858,7 @@ static bool _calcNeedsDefaultSpace(SharedParameterBindingContext& sharedContext) { default: break; - + case LayoutResourceKind::PushConstantBuffer: case LayoutResourceKind::RegisterSpace: case LayoutResourceKind::SubElementRegisterSpace: case LayoutResourceKind::VaryingInput: diff --git a/tests/diagnostics/specialization-constants.slang b/tests/diagnostics/specialization-constants.slang new file mode 100644 index 0000000000..30f3a5f95a --- /dev/null +++ b/tests/diagnostics/specialization-constants.slang @@ -0,0 +1,16 @@ +//DIAGNOSTIC_TEST:SIMPLE(filecheck=CHECK): -target spirv + +struct T { int x; int y; } + +// CHECK: ([[# @LINE+1]]): error 31218 +[vk::constant_id(1)] +const T st; + +[vk::constant_id(1)] +// CHECK: ([[# @LINE+1]]): error 31219 +static const int x = 2; + +[push_constant] +[vk::constant_id(1)] +// CHECK: ([[# @LINE+1]]): error 31220 +const int y; \ No newline at end of file diff --git a/tests/spirv/push-constant-space.slang b/tests/spirv/push-constant-space.slang new file mode 100644 index 0000000000..847c60b7d0 --- /dev/null +++ b/tests/spirv/push-constant-space.slang @@ -0,0 +1,18 @@ +// Test that push constants should not occupy the default +// space. + +//TEST:SIMPLE(filecheck=CHECK): -target spirv + +// CHECK-NOT: OpDecorate {{.*}} DescriptorSet 1 + +struct Data { + StructuredBuffer data; + RWStructuredBuffer output; +}; +ParameterBlock gData; + +[numthreads(1,1,1)] +void taskMain(uniform uint a) +{ + gData.output[0] = gData.data[0].x + a; +}