| 418 | } |
| 419 | |
| 420 | spv_result_t ValidateMemberDecorate(ValidationState_t& _, |
| 421 | const Instruction* inst) { |
| 422 | const auto struct_type_id = inst->GetOperandAs<uint32_t>(0); |
| 423 | const auto struct_type = _.FindDef(struct_type_id); |
| 424 | const bool is_mem_dec_id_inst = |
| 425 | (inst->opcode() == spv::Op::OpMemberDecorateIdEXT); |
| 426 | if (!struct_type || spv::Op::OpTypeStruct != struct_type->opcode()) { |
| 427 | return _.diag(SPV_ERROR_INVALID_ID, inst) |
| 428 | << (is_mem_dec_id_inst ? "OpMemberDecorateIdEXT" |
| 429 | : "OpMemberDecorate") |
| 430 | << " Structure type <id> " << _.getIdName(struct_type_id) |
| 431 | << " is not a struct type."; |
| 432 | } |
| 433 | const auto member = inst->GetOperandAs<uint32_t>(1); |
| 434 | const auto member_count = |
| 435 | static_cast<uint32_t>(struct_type->words().size() - 2); |
| 436 | if (member_count <= member) { |
| 437 | return _.diag(SPV_ERROR_INVALID_ID, inst) |
| 438 | << "Index " << member << " provided in " |
| 439 | << (is_mem_dec_id_inst ? "OpMemberDecorateIdEXT" |
| 440 | : "OpMemberDecorate") |
| 441 | << " for struct <id> " << _.getIdName(struct_type_id) |
| 442 | << " is out of bounds. The structure has " << member_count |
| 443 | << " members. Largest valid index is " << member_count - 1 << "."; |
| 444 | } |
| 445 | |
| 446 | const auto decoration = inst->GetOperandAs<spv::Decoration>(2); |
| 447 | if (is_mem_dec_id_inst) { |
| 448 | if (decoration != spv::Decoration::OffsetIdEXT) { |
| 449 | if (decoration == spv::Decoration::ArrayStrideIdEXT) { |
| 450 | return _.diag(SPV_ERROR_INVALID_ID, inst) |
| 451 | << "ArrayStrideIdEXT could only be directly applied" |
| 452 | << " to array type using OpDecorateId."; |
| 453 | } else { |
| 454 | return _.diag(SPV_ERROR_INVALID_ID, inst) |
| 455 | << "Decoration operand could only be OffsetIdEXT."; |
| 456 | } |
| 457 | } |
| 458 | |
| 459 | const auto is_descriptor_type = [&_](const Instruction* type_inst) { |
| 460 | return _.IsDescriptorType(type_inst->opcode()); |
| 461 | }; |
| 462 | |
| 463 | // recursively scans the struct to find if anything has a descriptor type, |
| 464 | // must be at least 1 |
| 465 | if (decoration == spv::Decoration::OffsetIdEXT) { |
| 466 | const uint32_t operand_id = inst->GetOperandAs<uint32_t>(3); |
| 467 | if (!_.IsIntScalarType(_.GetTypeId(operand_id), 32)) { |
| 468 | return _.diag(SPV_ERROR_INVALID_ID, inst) |
| 469 | << "OffsetIdEXT extra operand must be a 32-bit int scalar type."; |
| 470 | } |
| 471 | if (!_.ContainsType(struct_type_id, is_descriptor_type, true)) { |
| 472 | return _.diag(SPV_ERROR_INVALID_ID, inst) |
| 473 | << "OffsetIdEXT decoration in MemberDecorateIdEXT must only be " |
| 474 | "applied to members of structs where the struct contains " |
| 475 | "descriptor types."; |
| 476 | } |
| 477 | } |
no test coverage detected