Validate Buffer and BufferBlock apply only to struct types (#3259)
diff --git a/source/val/validate_decorations.cpp b/source/val/validate_decorations.cpp
index 3b44833..ce09e18 100644
--- a/source/val/validate_decorations.cpp
+++ b/source/val/validate_decorations.cpp
@@ -1524,6 +1524,22 @@
return SPV_SUCCESS;
}
+// Returns SPV_SUCCESS if validation rules are satisfied for the Block
+// decoration. Otherwise emits a diagnostic and returns something other than
+// SPV_SUCCESS.
+spv_result_t CheckBlockDecoration(ValidationState_t& vstate,
+ const Instruction& inst,
+ const Decoration& decoration) {
+ assert(inst.id() && "Parser ensures the target of the decoration has an ID");
+ if (inst.opcode() != SpvOpTypeStruct) {
+ const char* const dec_name =
+ decoration.dec_type() == SpvDecorationBlock ? "Block" : "BufferBlock";
+ return vstate.diag(SPV_ERROR_INVALID_ID, &inst)
+ << dec_name << " decoration on a non-struct type.";
+ }
+ return SPV_SUCCESS;
+}
+
#define PASS_OR_BAIL_AT_LINE(X, LINE) \
{ \
spv_result_t e##LINE = (X); \
@@ -1570,6 +1586,10 @@
case SpvDecorationNoUnsignedWrap:
PASS_OR_BAIL(CheckIntegerWrapDecoration(vstate, *inst, decoration));
break;
+ case SpvDecorationBlock:
+ case SpvDecorationBufferBlock:
+ PASS_OR_BAIL(CheckBlockDecoration(vstate, *inst, decoration));
+ break;
default:
break;
}
diff --git a/test/val/val_capability_test.cpp b/test/val/val_capability_test.cpp
index 098fa2f..8580818 100644
--- a/test/val/val_capability_test.cpp
+++ b/test/val/val_capability_test.cpp
@@ -1229,14 +1229,18 @@
"%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid),
ShaderDependencies()),
std::make_pair(std::string(kOpenCLMemoryModel) +
+ // Block applies to struct type.
"OpEntryPoint Kernel %func \"compute\" \n"
- "OpDecorate %intt Block\n"
- "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid),
+ "OpDecorate %block Block\n"
+ "%intt = OpTypeInt 32 0\n"
+ "%block = OpTypeStruct %intt\n" + std::string(kVoidFVoid),
ShaderDependencies()),
std::make_pair(std::string(kOpenCLMemoryModel) +
+ // BufferBlock applies to struct type.
"OpEntryPoint Kernel %func \"compute\" \n"
- "OpDecorate %intt BufferBlock\n"
- "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid),
+ "OpDecorate %block BufferBlock\n"
+ "%intt = OpTypeInt 32 0\n"
+ "%block = OpTypeStruct %intt\n" + std::string(kVoidFVoid),
ShaderDependencies()),
std::make_pair(std::string(kOpenCLMemoryModel) +
"OpEntryPoint Kernel %func \"compute\" \n"
diff --git a/test/val/val_decoration_test.cpp b/test/val/val_decoration_test.cpp
index 256e115..ec25d58 100644
--- a/test/val/val_decoration_test.cpp
+++ b/test/val/val_decoration_test.cpp
@@ -700,6 +700,61 @@
EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
}
+TEST_F(ValidateDecorations, BlockDecoratingArrayBad) {
+ std::string spirv = R"(
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %main "main"
+ OpExecutionMode %main LocalSize 1 1 1
+ OpSource GLSL 430
+ OpDecorate %Output Block
+ %void = OpTypeVoid
+ %3 = OpTypeFunction %void
+ %float = OpTypeFloat 32
+ %int = OpTypeInt 32 1
+ %int_3 = OpConstant %int 3
+ %Output = OpTypeArray %float %int_3
+%_ptr_Uniform_Output = OpTypePointer Uniform %Output
+ %dataOutput = OpVariable %_ptr_Uniform_Output Uniform
+ %main = OpFunction %void None %3
+ %5 = OpLabel
+ OpReturn
+ OpFunctionEnd
+ )";
+
+ CompileSuccessfully(spirv);
+ EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("Block decoration on a non-struct type"));
+}
+
+TEST_F(ValidateDecorations, BlockDecoratingIntBad) {
+ std::string spirv = R"(
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %main "main"
+ OpExecutionMode %main LocalSize 1 1 1
+ OpSource GLSL 430
+ OpDecorate %Output Block
+ %void = OpTypeVoid
+ %3 = OpTypeFunction %void
+ %Output = OpTypeInt 32 1
+%_ptr_Uniform_Output = OpTypePointer Uniform %Output
+ %dataOutput = OpVariable %_ptr_Uniform_Output Uniform
+ %main = OpFunction %void None %3
+ %5 = OpLabel
+ OpReturn
+ OpFunctionEnd
+ )";
+
+ CompileSuccessfully(spirv);
+ EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("Block decoration on a non-struct type"));
+}
+
TEST_F(ValidateDecorations, BlockMissingOffsetBad) {
std::string spirv = R"(
OpCapability Shader