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>'");
|
||||
}
|
||||
|
||||
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) {
|
||||
// struct MyInputs {
|
||||
// [[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'");
|
||||
}
|
||||
|
||||
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) {
|
||||
// [[stage(fragment)]]
|
||||
// fn fs_main(
|
||||
|
|
|
@ -230,8 +230,7 @@ TEST_P(FunctionReturnTypeDecorationTest, IsValid) {
|
|||
auto& params = GetParam();
|
||||
|
||||
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) {
|
||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||
|
@ -244,6 +243,41 @@ TEST_P(FunctionReturnTypeDecorationTest, IsValid) {
|
|||
INSTANTIATE_TEST_SUITE_P(
|
||||
ResolverDecorationValidationTest,
|
||||
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},
|
||||
TestParams{DecorationKind::kBinding, false},
|
||||
TestParams{DecorationKind::kBuiltin, true},
|
||||
|
@ -258,9 +292,9 @@ INSTANTIATE_TEST_SUITE_P(
|
|||
TestParams{DecorationKind::kWorkgroup, false},
|
||||
TestParams{DecorationKind::kBindingAndGroup, false}));
|
||||
|
||||
TEST_F(FunctionReturnTypeDecorationTest, DuplicateDecoration) {
|
||||
TEST_F(EntryPointReturnTypeDecorationTest, DuplicateDecoration) {
|
||||
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{
|
||||
Location(Source{{12, 34}}, 2),
|
||||
Location(Source{{56, 78}}, 3),
|
||||
|
|
|
@ -1084,11 +1084,21 @@ bool Resolver::ValidateFunction(const ast::Function* func,
|
|||
}
|
||||
|
||||
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",
|
||||
deco->source());
|
||||
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