diff --git a/src/ast/transform/vertex_pulling_transform_test.cc b/src/ast/transform/vertex_pulling_transform_test.cc index 8f41ecf565..070a4c45f4 100644 --- a/src/ast/transform/vertex_pulling_transform_test.cc +++ b/src/ast/transform/vertex_pulling_transform_test.cc @@ -52,9 +52,6 @@ class VertexPullingTransformHelper { tint::TypeDeterminer td(&ctx_, mod_.get()); EXPECT_TRUE(td.Determine()); - tint::Validator v; - EXPECT_TRUE(v.Validate(mod_.get())); - transform_->SetVertexState( std::make_unique(std::move(vertex_state))); transform_->SetEntryPoint("main"); diff --git a/src/validator_function_test.cc b/src/validator_function_test.cc index e582defb0c..fda20fe9fb 100644 --- a/src/validator_function_test.cc +++ b/src/validator_function_test.cc @@ -47,7 +47,7 @@ class TypeDeterminerHelper { 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 @@ TEST_F(ValidateFunctionTest, DISABLED_FunctionEndWithoutReturnStatement_Fail) { 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 @@ TEST_F(ValidateFunctionTest, 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 b3301964d3..b597b2c608 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 @@ bool ValidatorImpl::ValidateFunction(const ast::Function* func) { 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 0a116b9ea5..9f4ada0f7e 100644 --- a/src/validator_test.cc +++ b/src/validator_test.cc @@ -316,6 +316,7 @@ TEST_F(ValidatorTest, UsingUndefinedVariableGlobalVariable_Pass) { // 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( @@ -330,6 +331,8 @@ TEST_F(ValidatorTest, UsingUndefinedVariableGlobalVariable_Pass) { auto rhs = std::make_unique( std::make_unique(&f32, 3.14f)); auto* rhs_ptr = rhs.get(); + auto return_expr = std::make_unique( + std::make_unique(&f32, 3.14f)); ast::VariableList params; auto func = @@ -338,6 +341,7 @@ TEST_F(ValidatorTest, UsingUndefinedVariableGlobalVariable_Pass) { auto body = std::make_unique(); body->append(std::make_unique( Source{12, 34}, std::move(lhs), std::move(rhs))); + body->append(std::make_unique(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, DISABLED_RedeclaredIdentifierInnerScope_False) { } 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("a", ast::StorageClass::kNone, &f32); var0->set_constructor(std::make_unique( std::make_unique(&f32, 2.0))); - auto var1 = - std::make_unique("a", ast::StorageClass::kNone, &f32); + auto var1 = std::make_unique("a", ast::StorageClass::kNone, + &void_type); var1->set_constructor(std::make_unique( std::make_unique(&f32, 1.0))); ast::VariableList params0; auto func0 = - std::make_unique("func0", std::move(params0), &f32); + std::make_unique("func0", std::move(params0), &void_type); auto body0 = std::make_unique(); body0->append(std::make_unique(Source{12, 34}, std::move(var0))); + body0->append(std::make_unique()); func0->set_body(std::move(body0)); ast::VariableList params1; @@ -672,6 +678,7 @@ TEST_F(ValidatorTest, RedeclaredIdentifierDifferentFunctions_Pass) { auto body1 = std::make_unique(); body1->append(std::make_unique(Source{13, 34}, std::move(var1))); + body1->append(std::make_unique()); func1->set_body(std::move(body1)); mod()->AddFunction(std::move(func0));