Validate attributes on function return types
Functions that are not entry points cannot have any attributes on their return types. Validate the builtin store types for return types. Bug: tint:851 Change-Id: I718356b3ab06db4b4502a53b81790e4de0ecfeac Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/56100 Auto-Submit: James Price <jrprice@google.com> Commit-Queue: Ben Clayton <bclayton@google.com> Kokoro: Kokoro <noreply+kokoro@google.com> Reviewed-by: Ben Clayton <bclayton@google.com>
This commit is contained in:
parent
67993b955e
commit
1b1d963d7b
|
@ -39,6 +39,18 @@ TEST_F(ResolverBuiltinsValidationTest, PositionNotF32_Struct_Fail) {
|
||||||
"12:34 error: store type of builtin(position) must be 'vec4<f32>'");
|
"12:34 error: store type of builtin(position) must be 'vec4<f32>'");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(ResolverBuiltinsValidationTest, PositionNotF32_ReturnType_Fail) {
|
||||||
|
// [[stage(vertex)]]
|
||||||
|
// fn main() -> [[builtin(position)]] f32 { return 1.0; }
|
||||||
|
Func("main", {}, ty.f32(), {Return(1.0f)},
|
||||||
|
{Stage(ast::PipelineStage::kVertex)},
|
||||||
|
{Builtin(Source{{12, 34}}, ast::Builtin::kPosition)});
|
||||||
|
|
||||||
|
EXPECT_FALSE(r()->Resolve());
|
||||||
|
EXPECT_EQ(r()->error(),
|
||||||
|
"12:34 error: store type of builtin(position) must be 'vec4<f32>'");
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(ResolverBuiltinsValidationTest, FragDepthNotF32_Struct_Fail) {
|
TEST_F(ResolverBuiltinsValidationTest, FragDepthNotF32_Struct_Fail) {
|
||||||
// struct MyInputs {
|
// struct MyInputs {
|
||||||
// [[builtin(kFragDepth)]] p: i32;
|
// [[builtin(kFragDepth)]] p: i32;
|
||||||
|
@ -77,6 +89,18 @@ TEST_F(ResolverBuiltinsValidationTest, SampleMaskNotU32_Struct_Fail) {
|
||||||
"12:34 error: store type of builtin(sample_mask) must be 'u32'");
|
"12:34 error: store type of builtin(sample_mask) must be 'u32'");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(ResolverBuiltinsValidationTest, SampleMaskNotU32_ReturnType_Fail) {
|
||||||
|
// [[stage(fragment)]]
|
||||||
|
// fn main() -> [[builtin(sample_mask)]] i32 { return 1; }
|
||||||
|
Func("main", {}, ty.i32(), {Return(1)},
|
||||||
|
{Stage(ast::PipelineStage::kFragment)},
|
||||||
|
{Builtin(Source{{12, 34}}, ast::Builtin::kSampleMask)});
|
||||||
|
|
||||||
|
EXPECT_FALSE(r()->Resolve());
|
||||||
|
EXPECT_EQ(r()->error(),
|
||||||
|
"12:34 error: store type of builtin(sample_mask) must be 'u32'");
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(ResolverBuiltinsValidationTest, SampleMaskIsNotU32_Fail) {
|
TEST_F(ResolverBuiltinsValidationTest, SampleMaskIsNotU32_Fail) {
|
||||||
// [[stage(fragment)]]
|
// [[stage(fragment)]]
|
||||||
// fn fs_main(
|
// fn fs_main(
|
||||||
|
|
|
@ -230,8 +230,7 @@ TEST_P(FunctionReturnTypeDecorationTest, IsValid) {
|
||||||
auto& params = GetParam();
|
auto& params = GetParam();
|
||||||
|
|
||||||
Func("main", ast::VariableList{}, ty.f32(), ast::StatementList{Return(1.f)},
|
Func("main", ast::VariableList{}, ty.f32(), ast::StatementList{Return(1.f)},
|
||||||
ast::DecorationList{Stage(ast::PipelineStage::kCompute)},
|
{}, createDecorations({}, *this, params.kind));
|
||||||
createDecorations({}, *this, params.kind));
|
|
||||||
|
|
||||||
if (params.should_pass) {
|
if (params.should_pass) {
|
||||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||||
|
@ -244,6 +243,41 @@ TEST_P(FunctionReturnTypeDecorationTest, IsValid) {
|
||||||
INSTANTIATE_TEST_SUITE_P(
|
INSTANTIATE_TEST_SUITE_P(
|
||||||
ResolverDecorationValidationTest,
|
ResolverDecorationValidationTest,
|
||||||
FunctionReturnTypeDecorationTest,
|
FunctionReturnTypeDecorationTest,
|
||||||
|
testing::Values(TestParams{DecorationKind::kAlign, false},
|
||||||
|
TestParams{DecorationKind::kBinding, false},
|
||||||
|
TestParams{DecorationKind::kBuiltin, false},
|
||||||
|
TestParams{DecorationKind::kGroup, false},
|
||||||
|
TestParams{DecorationKind::kLocation, false},
|
||||||
|
TestParams{DecorationKind::kOverride, false},
|
||||||
|
TestParams{DecorationKind::kOffset, false},
|
||||||
|
TestParams{DecorationKind::kSize, false},
|
||||||
|
TestParams{DecorationKind::kStage, false},
|
||||||
|
TestParams{DecorationKind::kStride, false},
|
||||||
|
TestParams{DecorationKind::kStructBlock, false},
|
||||||
|
TestParams{DecorationKind::kWorkgroup, false},
|
||||||
|
TestParams{DecorationKind::kBindingAndGroup, false}));
|
||||||
|
|
||||||
|
using EntryPointReturnTypeDecorationTest = TestWithParams;
|
||||||
|
TEST_P(EntryPointReturnTypeDecorationTest, IsValid) {
|
||||||
|
auto& params = GetParam();
|
||||||
|
|
||||||
|
Func("main", ast::VariableList{}, ty.vec4<f32>(),
|
||||||
|
{Return(Construct(ty.vec4<f32>(), 1.f))},
|
||||||
|
{Stage(ast::PipelineStage::kCompute)},
|
||||||
|
createDecorations({}, *this, params.kind));
|
||||||
|
|
||||||
|
if (params.should_pass) {
|
||||||
|
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||||
|
} else {
|
||||||
|
EXPECT_FALSE(r()->Resolve()) << r()->error();
|
||||||
|
EXPECT_EQ(r()->error(),
|
||||||
|
"error: decoration is not valid for entry point return types");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
INSTANTIATE_TEST_SUITE_P(
|
||||||
|
ResolverDecorationValidationTest,
|
||||||
|
EntryPointReturnTypeDecorationTest,
|
||||||
testing::Values(TestParams{DecorationKind::kAlign, false},
|
testing::Values(TestParams{DecorationKind::kAlign, false},
|
||||||
TestParams{DecorationKind::kBinding, false},
|
TestParams{DecorationKind::kBinding, false},
|
||||||
TestParams{DecorationKind::kBuiltin, true},
|
TestParams{DecorationKind::kBuiltin, true},
|
||||||
|
@ -258,9 +292,9 @@ INSTANTIATE_TEST_SUITE_P(
|
||||||
TestParams{DecorationKind::kWorkgroup, false},
|
TestParams{DecorationKind::kWorkgroup, false},
|
||||||
TestParams{DecorationKind::kBindingAndGroup, false}));
|
TestParams{DecorationKind::kBindingAndGroup, false}));
|
||||||
|
|
||||||
TEST_F(FunctionReturnTypeDecorationTest, DuplicateDecoration) {
|
TEST_F(EntryPointReturnTypeDecorationTest, DuplicateDecoration) {
|
||||||
Func("main", ast::VariableList{}, ty.f32(), ast::StatementList{Return(1.f)},
|
Func("main", ast::VariableList{}, ty.f32(), ast::StatementList{Return(1.f)},
|
||||||
ast::DecorationList{Stage(ast::PipelineStage::kCompute)},
|
ast::DecorationList{Stage(ast::PipelineStage::kFragment)},
|
||||||
ast::DecorationList{
|
ast::DecorationList{
|
||||||
Location(Source{{12, 34}}, 2),
|
Location(Source{{12, 34}}, 2),
|
||||||
Location(Source{{56, 78}}, 3),
|
Location(Source{{56, 78}}, 3),
|
||||||
|
|
|
@ -1084,11 +1084,21 @@ bool Resolver::ValidateFunction(const ast::Function* func,
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto* deco : func->return_type_decorations()) {
|
for (auto* deco : func->return_type_decorations()) {
|
||||||
if (!deco->IsAnyOf<ast::BuiltinDecoration, ast::LocationDecoration>()) {
|
if (!func->IsEntryPoint()) {
|
||||||
AddError("decoration is not valid for function return types",
|
AddError("decoration is not valid for function return types",
|
||||||
deco->source());
|
deco->source());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (auto* builtin = deco->As<ast::BuiltinDecoration>()) {
|
||||||
|
if (!ValidateBuiltinDecoration(builtin, info->return_type)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else if (!deco->Is<ast::LocationDecoration>()) {
|
||||||
|
AddError("decoration is not valid for entry point return types",
|
||||||
|
deco->source());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue