[validation] check if at least one of vertex, fragment or compute shader is peresent

Bug: tint: 6
Change-Id: I826d951c374409699082f38fb65225f5b4a83f2d
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/27483
Commit-Queue: Sarah Mashayekhi <sarahmashay@google.com>
Commit-Queue: dan sinclair <dsinclair@chromium.org>
Reviewed-by: dan sinclair <dsinclair@chromium.org>
diff --git a/src/validator_function_test.cc b/src/validator_function_test.cc
index 864d9cb..178a930 100644
--- a/src/validator_function_test.cc
+++ b/src/validator_function_test.cc
@@ -402,5 +402,45 @@
   EXPECT_TRUE(v()->Validate(mod())) << v()->error();
 }
 
+TEST_F(ValidateFunctionTest,
+       AtLeastOneOfVertexFragmentComputeShaderMustBePeresent_Pass) {
+  // entry_point vertex as "main" = vtx_func
+  // fn vtx_func() -> void { return; }
+  ast::type::VoidType void_type;
+  ast::VariableList params;
+  auto func = std::make_unique<ast::Function>("vtx_func", std::move(params),
+                                              &void_type);
+  auto body = std::make_unique<ast::BlockStatement>();
+  body->append(std::make_unique<ast::ReturnStatement>());
+  func->set_body(std::move(body));
+
+  auto entry_point = std::make_unique<ast::EntryPoint>(
+      ast::PipelineStage::kVertex, "main", "vtx_func");
+  mod()->AddFunction(std::move(func));
+  mod()->AddEntryPoint(std::move(entry_point));
+
+  EXPECT_TRUE(td()->Determine()) << td()->error();
+  EXPECT_TRUE(v()->Validate(mod())) << v()->error();
+}
+
+TEST_F(ValidateFunctionTest,
+       AtLeastOneOfVertexFragmentComputeShaderMustBePeresent_Fail) {
+  // fn vtx_func() -> void { return; }
+  ast::type::VoidType void_type;
+  ast::VariableList params;
+  auto func = std::make_unique<ast::Function>("vtx_func", std::move(params),
+                                              &void_type);
+  auto body = std::make_unique<ast::BlockStatement>();
+  body->append(std::make_unique<ast::ReturnStatement>());
+  func->set_body(std::move(body));
+  mod()->AddFunction(std::move(func));
+
+  EXPECT_TRUE(td()->Determine()) << td()->error();
+  EXPECT_FALSE(v()->Validate(mod()));
+  EXPECT_EQ(v()->error(),
+            "0:0: v-0003: At least one of vertex, fragment or compute shader "
+            "must be present");
+}
+
 }  // namespace
 }  // namespace tint
diff --git a/src/validator_impl.cc b/src/validator_impl.cc
index 9540a00..d504a93 100644
--- a/src/validator_impl.cc
+++ b/src/validator_impl.cc
@@ -112,6 +112,12 @@
     entry_point_map.set(ep_ptr->name(), ep_ptr->stage());
   }
 
+  if (eps.empty()) {
+    set_error(Source{0, 0},
+              "v-0003: At least one of vertex, fragment or compute shader must "
+              "be present");
+    return false;
+  }
   entry_point_map.pop_scope();
   return true;
 }
diff --git a/src/validator_test_helper.h b/src/validator_test_helper.h
index 990e2ab..282e5d8 100644
--- a/src/validator_test_helper.h
+++ b/src/validator_test_helper.h
@@ -37,7 +37,7 @@
   /// A handle to the created module
   /// @return a pointer to the test module
   ast::Module* mod() { return &mod_; }
-  /// Create a function and add an entry point to it
+  /// Creates a function and add an entry point to it
   void AddFakeEntryPoint();
 
  private:
@@ -45,6 +45,7 @@
   Context ctx_;
   ast::Module mod_;
   std::unique_ptr<TypeDeterminer> td_;
+  ast::type::VoidType void_type_;
 };
 
 }  // namespace tint