[tint][ir][fuzz] Handle malformed StoreVectorElement in validator

- Removes unused `CheckOperandsNotNull`

Issue: 345196551
Fixes: 355451180

Change-Id: I37ea66c826c66bf3a0e5174b2413d0a0ead651e9
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/200061
Reviewed-by: James Price <jrprice@google.com>
Commit-Queue: Ryan Harrison <rharrison@chromium.org>
Auto-Submit: Ryan Harrison <rharrison@chromium.org>
diff --git a/src/tint/lang/core/ir/store_vector_element.h b/src/tint/lang/core/ir/store_vector_element.h
index 9230bf0..22c29ed 100644
--- a/src/tint/lang/core/ir/store_vector_element.h
+++ b/src/tint/lang/core/ir/store_vector_element.h
@@ -47,6 +47,12 @@
     /// The offset in Operands() for the `value` value
     static constexpr size_t kValueOperandOffset = 2;
 
+    /// The fixed number of results returned by this instruction
+    static constexpr size_t kNumResults = 0;
+
+    /// The fixed number of operands used by this instruction
+    static constexpr size_t kNumOperands = 3;
+
     /// Constructor (no operands)
     StoreVectorElement();
 
diff --git a/src/tint/lang/core/ir/validator.cc b/src/tint/lang/core/ir/validator.cc
index a932edc..0406d33 100644
--- a/src/tint/lang/core/ir/validator.cc
+++ b/src/tint/lang/core/ir/validator.cc
@@ -364,15 +364,6 @@
     // TODO(345196551): Remove this override once it is no longer used.
     void CheckOperandNotNull(const ir::Instruction* inst, const ir::Value* operand, size_t idx);
 
-    /// Checks all operands in the given range (inclusive) for @p inst are not null
-    /// @param inst the instruction
-    /// @param start_operand the first operand to check
-    /// @param end_operand the last operand to check
-    // TODO(345196551): Remove this override once it is no longer used.
-    void CheckOperandsNotNull(const ir::Instruction* inst,
-                              size_t start_operand,
-                              size_t end_operand);
-
     /// Validates the root block
     /// @param blk the block
     void CheckRootBlock(const Block* blk);
@@ -911,16 +902,6 @@
     }
 }
 
-// TODO(353498500): Remove this function once it is no longer used.
-void Validator::CheckOperandsNotNull(const Instruction* inst,
-                                     size_t start_operand,
-                                     size_t end_operand) {
-    auto operands = inst->Operands();
-    for (size_t i = start_operand; i <= end_operand; i++) {
-        CheckOperandNotNull(inst, operands[i], i);
-    }
-}
-
 void Validator::CheckRootBlock(const Block* blk) {
     block_stack_.Push(blk);
     TINT_DEFER(block_stack_.Pop());
@@ -1871,9 +1852,10 @@
 }
 
 void Validator::CheckStoreVectorElement(const StoreVectorElement* s) {
-    CheckOperandsNotNull(s,  //
-                         StoreVectorElement::kToOperandOffset,
-                         StoreVectorElement::kValueOperandOffset);
+    if (!CheckResultsAndOperands(s, StoreVectorElement::kNumResults,
+                                 StoreVectorElement::kNumOperands)) {
+        return;
+    }
 
     if (auto* value = s->Value()) {
         if (auto* el_ty = GetVectorPtrElementType(s, StoreVectorElement::kToOperandOffset)) {
diff --git a/src/tint/lang/core/ir/validator_test.cc b/src/tint/lang/core/ir/validator_test.cc
index 538738d..1ba3dcc 100644
--- a/src/tint/lang/core/ir/validator_test.cc
+++ b/src/tint/lang/core/ir/validator_test.cc
@@ -5958,14 +5958,14 @@
 
     b.Append(f->Block(), [&] {
         b.Append(mod.allocators.instructions.Create<ir::StoreVectorElement>(
-            nullptr, b.Constant(1_i), b.Constant(2_i)));
+            nullptr, b.Constant(1_i), b.Constant(2_f)));
         b.Return(f);
     });
 
     auto res = ir::Validate(mod);
     ASSERT_NE(res, Success);
     EXPECT_EQ(res.Failure().reason.Str(), R"(:3:26 error: store_vector_element: operand is undefined
-    store_vector_element undef, 1i, 2i
+    store_vector_element undef, 1i, 2.0f
                          ^^^^^
 
 :2:3 note: in block
@@ -5975,7 +5975,7 @@
 note: # Disassembly
 %my_func = func():void {
   $B1: {
-    store_vector_element undef, 1i, 2i
+    store_vector_element undef, 1i, 2.0f
     ret
   }
 }
@@ -5988,33 +5988,25 @@
     b.Append(f->Block(), [&] {
         auto* var = b.Var(ty.ptr<function, vec3<f32>>());
         b.Append(mod.allocators.instructions.Create<ir::StoreVectorElement>(var->Result(0), nullptr,
-                                                                            b.Constant(2_i)));
+                                                                            b.Constant(2_f)));
         b.Return(f);
     });
 
     auto res = ir::Validate(mod);
     ASSERT_NE(res, Success);
     EXPECT_EQ(res.Failure().reason.Str(), R"(:4:30 error: store_vector_element: operand is undefined
-    store_vector_element %2, undef, 2i
+    store_vector_element %2, undef, 2.0f
                              ^^^^^
 
 :2:3 note: in block
   $B1: {
   ^^^
 
-:4:37 error: store_vector_element: value type 'i32' does not match vector pointer element type 'f32'
-    store_vector_element %2, undef, 2i
-                                    ^^
-
-:2:3 note: in block
-  $B1: {
-  ^^^
-
 note: # Disassembly
 %my_func = func():void {
   $B1: {
     %2:ptr<function, vec3<f32>, read_write> = var
-    store_vector_element %2, undef, 2i
+    store_vector_element %2, undef, 2.0f
     ret
   }
 }
@@ -6052,6 +6044,70 @@
 )");
 }
 
+TEST_F(IR_ValidatorTest, StoreVectorElement_MissingOperands) {
+    auto* f = b.Function("my_func", ty.void_());
+
+    b.Append(f->Block(), [&] {
+        auto* var = b.Var(ty.ptr<function, vec3<f32>>());
+        auto* store = b.StoreVectorElement(var, b.Constant(1_i), b.Constant(2_f));
+        store->ClearOperands();
+        b.Return(f);
+    });
+
+    auto res = ir::Validate(mod);
+    ASSERT_NE(res, Success);
+    EXPECT_EQ(res.Failure().reason.Str(),
+              R"(:4:5 error: store_vector_element: expected exactly 3 operands, got 0
+    store_vector_element 
+    ^^^^^^^^^^^^^^^^^^^^
+
+:2:3 note: in block
+  $B1: {
+  ^^^
+
+note: # Disassembly
+%my_func = func():void {
+  $B1: {
+    %2:ptr<function, vec3<f32>, read_write> = var
+    store_vector_element 
+    ret
+  }
+}
+)");
+}
+
+TEST_F(IR_ValidatorTest, StoreVectorElement_UnexpectedResult) {
+    auto* f = b.Function("my_func", ty.void_());
+
+    b.Append(f->Block(), [&] {
+        auto* var = b.Var(ty.ptr<function, vec3<f32>>());
+        auto* store = b.StoreVectorElement(var, b.Constant(1_i), b.Constant(2_f));
+        store->SetResults(Vector{b.InstructionResult(ty.f32())});
+        b.Return(f);
+    });
+
+    auto res = ir::Validate(mod);
+    ASSERT_NE(res, Success);
+    EXPECT_EQ(res.Failure().reason.Str(),
+              R"(:4:5 error: store_vector_element: expected exactly 0 results, got 1
+    store_vector_element %2, 1i, 2.0f
+    ^^^^^^^^^^^^^^^^^^^^
+
+:2:3 note: in block
+  $B1: {
+  ^^^
+
+note: # Disassembly
+%my_func = func():void {
+  $B1: {
+    %2:ptr<function, vec3<f32>, read_write> = var
+    store_vector_element %2, 1i, 2.0f
+    ret
+  }
+}
+)");
+}
+
 TEST_F(IR_ValidatorTest, Scoping_UseBeforeDecl) {
     auto* f = b.Function("my_func", ty.void_());