[validation] Validates return statement

This CL checks if functions end with a return statement (v-0002)
reworks previously added tests to pass
enables related tests

Bug: tint: 6
Change-Id: Iafe46581ccc50e146b33d33f9577d995a7f80d77
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/26722
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/ast/transform/vertex_pulling_transform_test.cc b/src/ast/transform/vertex_pulling_transform_test.cc
index 8f41ecf..070a4c4 100644
--- a/src/ast/transform/vertex_pulling_transform_test.cc
+++ b/src/ast/transform/vertex_pulling_transform_test.cc
@@ -52,9 +52,6 @@
     tint::TypeDeterminer td(&ctx_, mod_.get());
     EXPECT_TRUE(td.Determine());
 
-    tint::Validator v;
-    EXPECT_TRUE(v.Validate(mod_.get()));
-
     transform_->SetVertexState(
         std::make_unique<VertexStateDescriptor>(std::move(vertex_state)));
     transform_->SetEntryPoint("main");
diff --git a/src/validator_function_test.cc b/src/validator_function_test.cc
index e582def..fda20fe 100644
--- a/src/validator_function_test.cc
+++ b/src/validator_function_test.cc
@@ -47,7 +47,7 @@
 class ValidateFunctionTest : public TypeDeterminerHelper,
                              public testing::Test {};
 
-TEST_F(ValidateFunctionTest, DISABLED_FunctionEndWithoutReturnStatement_Fail) {
+TEST_F(ValidateFunctionTest, FunctionEndWithoutReturnStatement_Fail) {
   // fn func -> void { var a:i32 = 2; }
 
   ast::type::I32Type i32;
@@ -69,11 +69,10 @@
   tint::ValidatorImpl v;
   EXPECT_FALSE(v.Validate(mod()));
   EXPECT_EQ(v.error(),
-            "12:34: v-0002: 'function must end with a return statement 'func'");
+            "12:34: v-0002: function must end with a return statement");
 }
 
-TEST_F(ValidateFunctionTest,
-       DISABLED_FunctionEndWithoutReturnStatementEmptyBody_Fail) {
+TEST_F(ValidateFunctionTest, FunctionEndWithoutReturnStatementEmptyBody_Fail) {
   // fn func -> void {}
   ast::type::VoidType void_type;
   ast::VariableList params;
@@ -85,7 +84,7 @@
   tint::ValidatorImpl v;
   EXPECT_FALSE(v.Validate(mod()));
   EXPECT_EQ(v.error(),
-            "12:34: v-0002: 'function must end with a return statement 'func'");
+            "12:34: v-0002: function must end with a return statement");
 }
 
 }  // namespace
diff --git a/src/validator_impl.cc b/src/validator_impl.cc
index b330196..b597b2c 100644
--- a/src/validator_impl.cc
+++ b/src/validator_impl.cc
@@ -13,6 +13,7 @@
 // limitations under the License.
 
 #include "src/validator_impl.h"
+#include "src/ast/function.h"
 #include "src/ast/variable_decl_statement.h"
 
 namespace tint {
@@ -65,8 +66,13 @@
   if (!ValidateStatements(func->body())) {
     return false;
   }
-
   variable_stack_.pop_scope();
+
+  if (!func->get_last_statement() || !func->get_last_statement()->IsReturn()) {
+    set_error(func->source(),
+              "v-0002: function must end with a return statement");
+    return false;
+  }
   return true;
 }
 
diff --git a/src/validator_test.cc b/src/validator_test.cc
index 0a116b9..9f4ada0 100644
--- a/src/validator_test.cc
+++ b/src/validator_test.cc
@@ -316,6 +316,7 @@
   // var global_var: f32 = 2.1;
   // fn my_func() -> f32 {
   //   global_var = 3.14;
+  //   return 3.14;
   // }
   ast::type::F32Type f32;
   auto global_var = std::make_unique<ast::Variable>(
@@ -330,6 +331,8 @@
   auto rhs = std::make_unique<ast::ScalarConstructorExpression>(
       std::make_unique<ast::FloatLiteral>(&f32, 3.14f));
   auto* rhs_ptr = rhs.get();
+  auto return_expr = std::make_unique<ast::ScalarConstructorExpression>(
+      std::make_unique<ast::FloatLiteral>(&f32, 3.14f));
 
   ast::VariableList params;
   auto func =
@@ -338,6 +341,7 @@
   auto body = std::make_unique<ast::BlockStatement>();
   body->append(std::make_unique<ast::AssignmentStatement>(
       Source{12, 34}, std::move(lhs), std::move(rhs)));
+  body->append(std::make_unique<ast::ReturnStatement>(std::move(return_expr)));
   func->set_body(std::move(body));
   auto* func_ptr = func.get();
   mod()->AddFunction(std::move(func));
@@ -645,25 +649,27 @@
 }
 
 TEST_F(ValidatorTest, RedeclaredIdentifierDifferentFunctions_Pass) {
-  // func0 { var a : f32 = 2.0; }
-  // func1 { var a : f32 = 3.0; }
+  // func0 { var a : f32 = 2.0; return; }
+  // func1 { var a : f32 = 3.0; return; }
   ast::type::F32Type f32;
+  ast::type::VoidType void_type;
   auto var0 =
       std::make_unique<ast::Variable>("a", ast::StorageClass::kNone, &f32);
   var0->set_constructor(std::make_unique<ast::ScalarConstructorExpression>(
       std::make_unique<ast::FloatLiteral>(&f32, 2.0)));
 
-  auto var1 =
-      std::make_unique<ast::Variable>("a", ast::StorageClass::kNone, &f32);
+  auto var1 = std::make_unique<ast::Variable>("a", ast::StorageClass::kNone,
+                                              &void_type);
   var1->set_constructor(std::make_unique<ast::ScalarConstructorExpression>(
       std::make_unique<ast::FloatLiteral>(&f32, 1.0)));
 
   ast::VariableList params0;
   auto func0 =
-      std::make_unique<ast::Function>("func0", std::move(params0), &f32);
+      std::make_unique<ast::Function>("func0", std::move(params0), &void_type);
   auto body0 = std::make_unique<ast::BlockStatement>();
   body0->append(std::make_unique<ast::VariableDeclStatement>(Source{12, 34},
                                                              std::move(var0)));
+  body0->append(std::make_unique<ast::ReturnStatement>());
   func0->set_body(std::move(body0));
 
   ast::VariableList params1;
@@ -672,6 +678,7 @@
   auto body1 = std::make_unique<ast::BlockStatement>();
   body1->append(std::make_unique<ast::VariableDeclStatement>(Source{13, 34},
                                                              std::move(var1)));
+  body1->append(std::make_unique<ast::ReturnStatement>());
   func1->set_body(std::move(body1));
 
   mod()->AddFunction(std::move(func0));