Validate: (data) Block can't appear within a Block (#2410)
A Block or BufferBlock cannot be nested within another Block or BufferBlock
diff --git a/source/val/validate_type.cpp b/source/val/validate_type.cpp
index 6246ad5..a5428d7 100644
--- a/source/val/validate_type.cpp
+++ b/source/val/validate_type.cpp
@@ -237,6 +237,29 @@
}
}
+ bool has_nested_blockOrBufferBlock_struct = false;
+ // Struct members start at word 2 of OpTypeStruct instruction.
+ for (size_t word_i = 2; word_i < inst->words().size(); ++word_i) {
+ auto member = inst->word(word_i);
+ auto memberTypeInstr = _.FindDef(member);
+ if (memberTypeInstr && SpvOpTypeStruct == memberTypeInstr->opcode()) {
+ if (_.HasDecoration(memberTypeInstr->id(), SpvDecorationBlock) ||
+ _.HasDecoration(memberTypeInstr->id(), SpvDecorationBufferBlock) ||
+ _.GetHasNestedBlockOrBufferBlockStruct(memberTypeInstr->id()))
+ has_nested_blockOrBufferBlock_struct = true;
+ }
+ }
+
+ _.SetHasNestedBlockOrBufferBlockStruct(inst->id(),
+ has_nested_blockOrBufferBlock_struct);
+ if (_.GetHasNestedBlockOrBufferBlockStruct(inst->id()) &&
+ (_.HasDecoration(inst->id(), SpvDecorationBufferBlock) ||
+ _.HasDecoration(inst->id(), SpvDecorationBlock))) {
+ return _.diag(SPV_ERROR_INVALID_ID, inst)
+ << "rules: A Block or BufferBlock cannot be nested within another "
+ "Block or BufferBlock. ";
+ }
+
std::unordered_set<uint32_t> built_in_members;
for (auto decoration : _.id_decorations(struct_id)) {
if (decoration.dec_type() == SpvDecorationBuiltIn &&
diff --git a/source/val/validation_state.cpp b/source/val/validation_state.cpp
index 4a42935..2633963 100644
--- a/source/val/validation_state.cpp
+++ b/source/val/validation_state.cpp
@@ -168,6 +168,7 @@
global_vars_(),
local_vars_(),
struct_nesting_depth_(),
+ struct_has_nested_blockorbufferblock_struct_(),
grammar_(ctx),
addressing_model_(SpvAddressingModelMax),
memory_model_(SpvMemoryModelMax),
diff --git a/source/val/validation_state.h b/source/val/validation_state.h
index 676b423..55005a6 100644
--- a/source/val/validation_state.h
+++ b/source/val/validation_state.h
@@ -474,6 +474,18 @@
return struct_nesting_depth_[id];
}
+ /// Records the has a nested block/bufferblock decorated struct for a given
+ /// struct ID
+ void SetHasNestedBlockOrBufferBlockStruct(uint32_t id, bool has) {
+ struct_has_nested_blockorbufferblock_struct_[id] = has;
+ }
+
+ /// For a given struct ID returns true if it has a nested block/bufferblock
+ /// decorated struct
+ bool GetHasNestedBlockOrBufferBlockStruct(uint32_t id) {
+ return struct_has_nested_blockorbufferblock_struct_[id];
+ }
+
/// Records that the structure type has a member decorated with a built-in.
void RegisterStructTypeWithBuiltInMember(uint32_t id) {
builtin_structs_.insert(id);
@@ -716,6 +728,10 @@
/// Structure Nesting Depth
std::unordered_map<uint32_t, uint32_t> struct_nesting_depth_;
+ /// Structure has nested blockorbufferblock struct
+ std::unordered_map<uint32_t, bool>
+ struct_has_nested_blockorbufferblock_struct_;
+
/// Stores the list of decorations for a given <id>
std::map<uint32_t, std::vector<Decoration>> id_decorations_;
diff --git a/test/val/val_decoration_test.cpp b/test/val/val_decoration_test.cpp
index 35c780d..ccee09c 100644
--- a/test/val/val_decoration_test.cpp
+++ b/test/val/val_decoration_test.cpp
@@ -1510,6 +1510,158 @@
<< getDiagnosticString();
}
+TEST_F(ValidateDecorations, BlockCantAppearWithinABlockBad) {
+ // See https://github.com/KhronosGroup/SPIRV-Tools/issues/1587
+ std::string spirv = R"(
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Vertex %main "main"
+ OpSource GLSL 450
+ OpMemberDecorate %S 0 Offset 0
+ OpMemberDecorate %S 1 Offset 16
+ OpMemberDecorate %S2 0 Offset 0
+ OpMemberDecorate %S2 1 Offset 12
+ OpDecorate %S Block
+ OpDecorate %S2 Block
+ OpDecorate %B DescriptorSet 0
+ OpDecorate %B Binding 0
+ %void = OpTypeVoid
+ %3 = OpTypeFunction %void
+ %float = OpTypeFloat 32
+ %S2 = OpTypeStruct %float %float
+ %S = OpTypeStruct %float %S2
+%_ptr_Uniform_S = OpTypePointer Uniform %S
+ %B = OpVariable %_ptr_Uniform_S Uniform
+ %main = OpFunction %void None %3
+ %5 = OpLabel
+ OpReturn
+ OpFunctionEnd
+ )";
+
+ CompileSuccessfully(spirv);
+ EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("rules: A Block or BufferBlock cannot be nested within "
+ "another Block or BufferBlock."));
+}
+
+TEST_F(ValidateDecorations, BufferblockCantAppearWithinABufferblockBad) {
+ // See https://github.com/KhronosGroup/SPIRV-Tools/issues/1587
+ std::string spirv = R"(
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Vertex %main "main"
+ OpSource GLSL 450
+ OpMemberDecorate %S 0 Offset 0
+ OpMemberDecorate %S 1 Offset 16
+ OpMemberDecorate %S2 0 Offset 0
+ OpMemberDecorate %S2 1 Offset 16
+ OpMemberDecorate %S3 0 Offset 0
+ OpMemberDecorate %S3 1 Offset 12
+ OpDecorate %S BufferBlock
+ OpDecorate %S3 BufferBlock
+ OpDecorate %B DescriptorSet 0
+ OpDecorate %B Binding 0
+ %void = OpTypeVoid
+ %3 = OpTypeFunction %void
+ %float = OpTypeFloat 32
+ %S3 = OpTypeStruct %float %float
+ %S2 = OpTypeStruct %float %S3
+ %S = OpTypeStruct %float %S2
+%_ptr_Uniform_S = OpTypePointer Uniform %S
+ %B = OpVariable %_ptr_Uniform_S Uniform
+ %main = OpFunction %void None %3
+ %5 = OpLabel
+ OpReturn
+ OpFunctionEnd
+ )";
+
+ CompileSuccessfully(spirv);
+ EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("rules: A Block or BufferBlock cannot be nested within "
+ "another Block or BufferBlock."));
+}
+
+TEST_F(ValidateDecorations, BufferblockCantAppearWithinABlockBad) {
+ // See https://github.com/KhronosGroup/SPIRV-Tools/issues/1587
+ std::string spirv = R"(
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Vertex %main "main"
+ OpSource GLSL 450
+ OpMemberDecorate %S 0 Offset 0
+ OpMemberDecorate %S 1 Offset 16
+ OpMemberDecorate %S2 0 Offset 0
+ OpMemberDecorate %S2 1 Offset 16
+ OpMemberDecorate %S3 0 Offset 0
+ OpMemberDecorate %S3 1 Offset 12
+ OpDecorate %S Block
+ OpDecorate %S3 BufferBlock
+ OpDecorate %B DescriptorSet 0
+ OpDecorate %B Binding 0
+ %void = OpTypeVoid
+ %3 = OpTypeFunction %void
+ %float = OpTypeFloat 32
+ %S3 = OpTypeStruct %float %float
+ %S2 = OpTypeStruct %float %S3
+ %S = OpTypeStruct %float %S2
+%_ptr_Uniform_S = OpTypePointer Uniform %S
+ %B = OpVariable %_ptr_Uniform_S Uniform
+ %main = OpFunction %void None %3
+ %5 = OpLabel
+ OpReturn
+ OpFunctionEnd
+ )";
+
+ CompileSuccessfully(spirv);
+ EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("rules: A Block or BufferBlock cannot be nested within "
+ "another Block or BufferBlock."));
+}
+
+TEST_F(ValidateDecorations, BlockCantAppearWithinABufferblockBad) {
+ // See https://github.com/KhronosGroup/SPIRV-Tools/issues/1587
+ std::string spirv = R"(
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Vertex %main "main"
+ OpSource GLSL 450
+ OpMemberDecorate %S 0 Offset 0
+ OpMemberDecorate %S 1 Offset 16
+ OpMemberDecorate %S2 0 Offset 0
+ OpMemberDecorate %S2 1 Offset 16
+ OpMemberDecorate %S3 0 Offset 0
+ OpMemberDecorate %S3 1 Offset 16
+ OpMemberDecorate %S4 0 Offset 0
+ OpMemberDecorate %S4 1 Offset 12
+ OpDecorate %S BufferBlock
+ OpDecorate %S4 Block
+ OpDecorate %B DescriptorSet 0
+ OpDecorate %B Binding 0
+ %void = OpTypeVoid
+ %3 = OpTypeFunction %void
+ %float = OpTypeFloat 32
+ %S4 = OpTypeStruct %float %float
+ %S3 = OpTypeStruct %float %S4
+ %S2 = OpTypeStruct %float %S3
+ %S = OpTypeStruct %float %S2
+%_ptr_Uniform_S = OpTypePointer Uniform %S
+ %B = OpVariable %_ptr_Uniform_S Uniform
+ %main = OpFunction %void None %3
+ %5 = OpLabel
+ OpReturn
+ OpFunctionEnd
+ )";
+
+ CompileSuccessfully(spirv);
+ EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("rules: A Block or BufferBlock cannot be nested within "
+ "another Block or BufferBlock."));
+}
+
TEST_F(ValidateDecorations, BlockLayoutForbidsTightScalarVec3PackingBad) {
// See https://github.com/KhronosGroup/SPIRV-Tools/issues/1666
std::string spirv = R"(