validation: validate function parameters

A function parameter of pointer type must be in one of the following storage classes:
- function
- private
- workgroup

A function parameter must one the following types:
- atomic-free plain type
- a pointer type
- a texture type
- a sampler type

Bug: tint:896 tint:894
Change-Id: Id8cec1bdc8e5be2c8c18a8420cec8f13f6aeddd0
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/55940
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: Antonio Maiorano <amaiorano@google.com>
This commit is contained in:
Sarah 2021-06-29 15:24:04 +00:00 committed by Sarah Mashayekhi
parent 5a88ec8822
commit 9432c97070
3 changed files with 95 additions and 4 deletions

View File

@ -521,5 +521,65 @@ TEST_F(ResolverFunctionValidationTest, ReturnIsAtomicFreePlain_StructOfAtomic) {
"12:34 error: function return type must be an atomic-free plain type"); "12:34 error: function return type must be an atomic-free plain type");
} }
TEST_F(ResolverFunctionValidationTest, ParameterSotreType_NonAtomicFree) {
Structure("S", {Member("m", ty.atomic(ty.i32()))});
auto* ret_type = ty.type_name(Source{{12, 34}}, "S");
auto* bar = Param(Source{{12, 34}}, "bar", ret_type);
Func("f", ast::VariableList{bar}, ty.void_(), {});
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
"12:34 error: store type of function parameter must be an "
"atomic-free type");
}
TEST_F(ResolverFunctionValidationTest, ParameterSotreType_AtomicFree) {
Structure("S", {Member("m", ty.i32())});
auto* ret_type = ty.type_name(Source{{12, 34}}, "S");
auto* bar = Param(Source{{12, 34}}, "bar", ret_type);
Func("f", ast::VariableList{bar}, ty.void_(), {});
EXPECT_TRUE(r()->Resolve()) << r()->error();
}
struct TestParams {
ast::StorageClass storage_class;
bool should_pass;
};
struct TestWithParams : resolver::ResolverTestWithParam<TestParams> {};
using ResolverFunctionParameterValidationTest = TestWithParams;
TEST_P(ResolverFunctionParameterValidationTest, SotrageClass) {
auto& param = GetParam();
auto* ptr_type = ty.pointer(Source{{12, 34}}, ty.i32(), param.storage_class);
auto* arg = Param(Source{{12, 34}}, "p", ptr_type);
Func("f", ast::VariableList{arg}, ty.void_(), {});
if (param.should_pass) {
EXPECT_TRUE(r()->Resolve()) << r()->error();
} else {
std::stringstream ss;
ss << param.storage_class;
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
"12:34 error: function parameter of pointer type cannot be in '" +
ss.str() + "' storage class");
}
}
INSTANTIATE_TEST_SUITE_P(
ResolverTest,
ResolverFunctionParameterValidationTest,
testing::Values(TestParams{ast::StorageClass::kNone, false},
TestParams{ast::StorageClass::kInput, false},
TestParams{ast::StorageClass::kOutput, false},
TestParams{ast::StorageClass::kUniform, false},
TestParams{ast::StorageClass::kWorkgroup, true},
TestParams{ast::StorageClass::kUniformConstant, false},
TestParams{ast::StorageClass::kStorage, false},
TestParams{ast::StorageClass::kImage, false},
TestParams{ast::StorageClass::kPrivate, true},
TestParams{ast::StorageClass::kFunction, true}));
} // namespace } // namespace
} // namespace tint } // namespace tint

View File

@ -916,8 +916,8 @@ bool Resolver::ValidateVariable(const VariableInfo* info) {
return true; return true;
} }
bool Resolver::ValidateParameter(const ast::Function* func, bool Resolver::ValidateFunctionParameter(const ast::Function* func,
const VariableInfo* info) { const VariableInfo* info) {
if (!ValidateVariable(info)) { if (!ValidateVariable(info)) {
return false; return false;
} }
@ -953,6 +953,36 @@ bool Resolver::ValidateParameter(const ast::Function* func,
return false; return false;
} }
} }
if (auto* ref = info->type->As<sem::Pointer>()) {
auto sc = ref->StorageClass();
if (!(sc == ast::StorageClass::kFunction ||
sc == ast::StorageClass::kPrivate ||
sc == ast::StorageClass::kWorkgroup)) {
std::stringstream ss;
ss << "function parameter of pointer type cannot be in '" << sc
<< "' storage class";
AddError(ss.str(), info->declaration->source());
return false;
}
}
if (IsPlain(info->type)) {
if (!IsAtomicFreePlain(info->type) &&
!IsValidationDisabled(
info->declaration->decorations(),
ast::DisabledValidation::kIgnoreAtomicFunctionParameter)) {
AddError("store type of function parameter must be an atomic-free type",
info->declaration->source());
return false;
}
} else if (!info->type->IsAnyOf<sem::Texture, sem::Sampler, sem::Pointer>()) {
AddError("store type of function parameter cannot be " +
info->type->FriendlyName(builder_->Symbols()),
info->declaration->source());
return false;
}
return true; return true;
} }
@ -1077,7 +1107,7 @@ bool Resolver::ValidateFunction(const ast::Function* func,
} }
for (auto* param : func->params()) { for (auto* param : func->params()) {
if (!ValidateParameter(func, variable_to_info_.at(param))) { if (!ValidateFunctionParameter(func, variable_to_info_.at(param))) {
return false; return false;
} }
} }

View File

@ -281,7 +281,8 @@ class Resolver {
bool ValidateMatrix(const sem::Matrix* matirx_type, const Source& source); bool ValidateMatrix(const sem::Matrix* matirx_type, const Source& source);
bool ValidateMatrixConstructor(const ast::TypeConstructorExpression* ctor, bool ValidateMatrixConstructor(const ast::TypeConstructorExpression* ctor,
const sem::Matrix* matrix_type); const sem::Matrix* matrix_type);
bool ValidateParameter(const ast::Function* func, const VariableInfo* info); bool ValidateFunctionParameter(const ast::Function* func,
const VariableInfo* info);
bool ValidateReturn(const ast::ReturnStatement* ret); bool ValidateReturn(const ast::ReturnStatement* ret);
bool ValidateStatements(const ast::StatementList& stmts); bool ValidateStatements(const ast::StatementList& stmts);
bool ValidateStorageTexture(const ast::StorageTexture* t); bool ValidateStorageTexture(const ast::StorageTexture* t);