diff --git a/src/validator/validator_impl.cc b/src/validator/validator_impl.cc index 5aa6f0ae0d..3461e51a8e 100644 --- a/src/validator/validator_impl.cc +++ b/src/validator/validator_impl.cc @@ -29,8 +29,10 @@ #include "src/ast/switch_statement.h" #include "src/ast/type/array_type.h" #include "src/ast/type/i32_type.h" +#include "src/ast/type/matrix_type.h" #include "src/ast/type/struct_type.h" #include "src/ast/type/u32_type.h" +#include "src/ast/type/vector_type.h" #include "src/ast/type/void_type.h" #include "src/ast/uint_literal.h" #include "src/ast/variable_decl_statement.h" @@ -506,4 +508,29 @@ bool ValidatorImpl::ValidateIdentifier(const ast::IdentifierExpression* ident) { return true; } +bool ValidatorImpl::IsStorable(ast::type::Type* type) { + if (type == nullptr) { + return false; + } + if (type->is_scalar() || type->Is() || + type->Is()) { + return true; + } + if (ast::type::Array* array_type = type->As()) { + return IsStorable(array_type->type()); + } + if (ast::type::Struct* struct_type = type->As()) { + for (const auto* member : struct_type->impl()->members()) { + if (!IsStorable(member->type())) { + return false; + } + } + return true; + } + if (ast::type::Alias* alias_type = type->As()) { + return IsStorable(alias_type->type()); + } + return false; +} + } // namespace tint diff --git a/src/validator/validator_impl.h b/src/validator/validator_impl.h index 0a77654e42..d619b82212 100644 --- a/src/validator/validator_impl.h +++ b/src/validator/validator_impl.h @@ -17,6 +17,7 @@ #include #include +#include #include #include "src/ast/assignment_statement.h" @@ -147,6 +148,12 @@ class ValidatorImpl { bool ValidateConstructedTypes( const std::vector& constructed_types); + /// Returns true if the given type is storable. This uses and + /// updates `storable_` and `not_storable_`. + /// @param type the given type + /// @returns true if the given type is storable. + bool IsStorable(ast::type::Type* type); + private: const ast::Module& module_; diag::List diags_; diff --git a/src/validator/validator_test.cc b/src/validator/validator_test.cc index eacc3e39d5..1aa10f5cab 100644 --- a/src/validator/validator_test.cc +++ b/src/validator/validator_test.cc @@ -579,5 +579,86 @@ TEST_F(ValidatorTest, VariableDeclNoConstructor_Pass) { EXPECT_TRUE(v()->ValidateStatements(body)) << v()->error(); } +TEST_F(ValidatorTest, IsStorable_Void) { + EXPECT_FALSE(v()->IsStorable(ty.void_)); +} + +TEST_F(ValidatorTest, IsStorable_Scalar) { + EXPECT_TRUE(v()->IsStorable(ty.bool_)); + EXPECT_TRUE(v()->IsStorable(ty.i32)); + EXPECT_TRUE(v()->IsStorable(ty.u32)); + EXPECT_TRUE(v()->IsStorable(ty.f32)); +} + +TEST_F(ValidatorTest, IsStorable_Vector) { + EXPECT_TRUE(v()->IsStorable(ty.vec2())); + EXPECT_TRUE(v()->IsStorable(ty.vec3())); + EXPECT_TRUE(v()->IsStorable(ty.vec4())); + EXPECT_TRUE(v()->IsStorable(ty.vec2())); + EXPECT_TRUE(v()->IsStorable(ty.vec3())); + EXPECT_TRUE(v()->IsStorable(ty.vec4())); + EXPECT_TRUE(v()->IsStorable(ty.vec2())); + EXPECT_TRUE(v()->IsStorable(ty.vec3())); + EXPECT_TRUE(v()->IsStorable(ty.vec4())); +} + +TEST_F(ValidatorTest, IsStorable_Matrix) { + EXPECT_TRUE(v()->IsStorable(ty.mat2x2())); + EXPECT_TRUE(v()->IsStorable(ty.mat2x3())); + EXPECT_TRUE(v()->IsStorable(ty.mat2x4())); + EXPECT_TRUE(v()->IsStorable(ty.mat3x2())); + EXPECT_TRUE(v()->IsStorable(ty.mat3x3())); + EXPECT_TRUE(v()->IsStorable(ty.mat3x4())); + EXPECT_TRUE(v()->IsStorable(ty.mat4x2())); + EXPECT_TRUE(v()->IsStorable(ty.mat4x3())); + EXPECT_TRUE(v()->IsStorable(ty.mat4x4())); +} + +TEST_F(ValidatorTest, IsStorable_Pointer) { + auto* ptr_ty = ty.pointer(ast::StorageClass::kPrivate); + EXPECT_FALSE(v()->IsStorable(ptr_ty)); +} + +TEST_F(ValidatorTest, IsStorable_AliasVoid) { + auto* alias = ty.alias("myalias", ty.void_); + EXPECT_FALSE(v()->IsStorable(alias)); +} + +TEST_F(ValidatorTest, IsStorable_AliasI32) { + auto* alias = ty.alias("myalias", ty.i32); + EXPECT_TRUE(v()->IsStorable(alias)); +} + +TEST_F(ValidatorTest, IsStorable_ArraySizedOfStorable) { + EXPECT_TRUE(v()->IsStorable(ty.array(ty.i32, 5))); +} + +TEST_F(ValidatorTest, IsStorable_ArraySizedOfNonStorable) { + EXPECT_FALSE(v()->IsStorable(ty.array(ty.void_, 5))); +} + +TEST_F(ValidatorTest, IsStorable_ArrayUnsizedOfStorable) { + EXPECT_TRUE(v()->IsStorable(ty.array())); +} + +TEST_F(ValidatorTest, IsStorable_ArrayUnsizedOfNonStorable) { + EXPECT_FALSE(v()->IsStorable(ty.array())); +} + +TEST_F(ValidatorTest, IsStorable_Struct_AllMembersStorable) { + ast::StructMemberList members{Member("a", ty.i32), Member("b", ty.f32)}; + auto* s = create(Source{}, members, ast::StructDecorationList{}); + auto* s_ty = ty.struct_("mystruct", s); + EXPECT_TRUE(v()->IsStorable(s_ty)); +} + +TEST_F(ValidatorTest, IsStorable_Struct_SomeMembersNonStorable) { + auto* ptr_ty = ty.pointer(ast::StorageClass::kPrivate); + ast::StructMemberList members{Member("a", ty.i32), Member("b", ptr_ty)}; + auto* s = create(Source{}, members, ast::StructDecorationList{}); + auto* s_ty = ty.struct_("mystruct", s); + EXPECT_FALSE(v()->IsStorable(s_ty)); +} + } // namespace } // namespace tint