resolver: Reject non-storage runtime-sized arrays

There were several cases where we were not rejecting these which were
leading to ICEs or bad codegen.

Fixed: tint:1248
Change-Id: I7cdf3b74d92b81b1067ad908af423ea0b5442328
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/76161
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: Ben Clayton <bclayton@google.com>
This commit is contained in:
James Price 2022-01-12 20:51:36 +00:00
parent 13c79bef23
commit db2f5fcf10
5 changed files with 99 additions and 28 deletions

View File

@ -2650,6 +2650,14 @@ bool Resolver::ApplyStorageClassUsageToType(ast::StorageClass sc,
}
if (auto* arr = ty->As<sem::Array>()) {
if (arr->IsRuntimeSized() && sc != ast::StorageClass::kStorage) {
AddError(
"runtime-sized arrays can only be used in the <storage> storage "
"class",
usage);
return false;
}
return ApplyStorageClassUsageToType(
sc, const_cast<sem::Type*>(arr->ElemType()), usage);
}

View File

@ -571,19 +571,6 @@ bool Resolver::ValidateGlobalVariable(const sem::Variable* var) {
decl->source);
return false;
}
for (auto* member : str->Members()) {
if (auto* arr = member->Type()->As<sem::Array>()) {
if (arr->IsRuntimeSized()) {
AddError(
"structure containing a runtime sized array "
"cannot be used as a uniform buffer",
decl->source);
AddNote("structure is declared here", str->Declaration()->source);
return false;
}
}
}
break;
}
default:

View File

@ -45,6 +45,52 @@ TEST_F(ResolverStorageClassValidationTest,
"the function storage class");
}
TEST_F(ResolverStorageClassValidationTest, Private_RuntimeArray) {
Global(Source{{12, 34}}, "v", ty.array(ty.i32()),
ast::StorageClass::kPrivate);
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(
r()->error(),
R"(12:34 error: runtime-sized arrays can only be used in the <storage> storage class
12:34 note: while instantiating variable v)");
}
TEST_F(ResolverStorageClassValidationTest, Private_RuntimeArrayInStruct) {
auto* s = Structure("S", {Member("m", ty.array(ty.i32()))}, {StructBlock()});
Global(Source{{12, 34}}, "v", ty.Of(s), ast::StorageClass::kPrivate);
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(
r()->error(),
R"(12:34 error: runtime-sized arrays can only be used in the <storage> storage class
note: while analysing structure member S.m
12:34 note: while instantiating variable v)");
}
TEST_F(ResolverStorageClassValidationTest, Workgroup_RuntimeArray) {
Global(Source{{12, 34}}, "v", ty.array(ty.i32()),
ast::StorageClass::kWorkgroup);
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(
r()->error(),
R"(12:34 error: runtime-sized arrays can only be used in the <storage> storage class
12:34 note: while instantiating variable v)");
}
TEST_F(ResolverStorageClassValidationTest, Workgroup_RuntimeArrayInStruct) {
auto* s = Structure("S", {Member("m", ty.array(ty.i32()))}, {StructBlock()});
Global(Source{{12, 34}}, "v", ty.Of(s), ast::StorageClass::kWorkgroup);
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(
r()->error(),
R"(12:34 error: runtime-sized arrays can only be used in the <storage> storage class
note: while analysing structure member S.m
12:34 note: while instantiating variable v)");
}
TEST_F(ResolverStorageClassValidationTest, StorageBufferBool) {
// var<storage> g : i32;
Global(Source{{56, 78}}, "g", ty.i32(), ast::StorageClass::kStorage,
@ -170,9 +216,11 @@ TEST_F(ResolverStorageClassValidationTest, UniformBuffer_Struct_Runtime) {
});
ASSERT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
"56:78 error: structure containing a runtime sized array cannot be "
"used as a uniform buffer\n12:34 note: structure is declared here");
EXPECT_EQ(
r()->error(),
R"(56:78 error: runtime-sized arrays can only be used in the <storage> storage class
note: while analysing structure member S.m
56:78 note: while instantiating variable svar)");
}
TEST_F(ResolverStorageClassValidationTest, UniformBufferBool) {

View File

@ -411,9 +411,10 @@ TEST_F(ResolverTypeValidationTest, RuntimeArrayInFunction_Fail) {
});
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
"12:34 error: runtime arrays may only appear as the last member of "
"a struct");
EXPECT_EQ(
r()->error(),
R"(12:34 error: runtime-sized arrays can only be used in the <storage> storage class
12:34 note: while instantiating variable a)");
}
TEST_F(ResolverTypeValidationTest, Struct_Member_VectorNoType) {
@ -575,7 +576,8 @@ TEST_F(ResolverTypeValidationTest, RuntimeArrayAsGlobalVariable) {
EXPECT_EQ(
r()->error(),
R"(56:78 error: runtime arrays may only appear as the last member of a struct)");
R"(56:78 error: runtime-sized arrays can only be used in the <storage> storage class
56:78 note: while instantiating variable g)");
}
TEST_F(ResolverTypeValidationTest, RuntimeArrayAsLocalVariable) {
@ -586,7 +588,8 @@ TEST_F(ResolverTypeValidationTest, RuntimeArrayAsLocalVariable) {
EXPECT_EQ(
r()->error(),
R"(56:78 error: runtime arrays may only appear as the last member of a struct)");
R"(56:78 error: runtime-sized arrays can only be used in the <storage> storage class
56:78 note: while instantiating variable g)");
}
TEST_F(ResolverTypeValidationTest, RuntimeArrayAsParameter_Fail) {
@ -610,9 +613,30 @@ TEST_F(ResolverTypeValidationTest, RuntimeArrayAsParameter_Fail) {
});
EXPECT_FALSE(r()->Resolve()) << r()->error();
EXPECT_EQ(r()->error(),
"12:34 error: runtime arrays may only appear as the last member of "
"a struct");
EXPECT_EQ(
r()->error(),
R"(12:34 error: runtime-sized arrays can only be used in the <storage> storage class
12:34 note: while instantiating parameter a)");
}
TEST_F(ResolverTypeValidationTest, PtrToRuntimeArrayAsParameter_Fail) {
// fn func(a : ptr<workgroup, array<u32>>) {}
auto* param =
Param(Source{{12, 34}}, "a",
ty.pointer(ty.array<i32>(), ast::StorageClass::kWorkgroup));
Func("func", ast::VariableList{param}, ty.void_(),
ast::StatementList{
Return(),
},
ast::DecorationList{});
EXPECT_FALSE(r()->Resolve()) << r()->error();
EXPECT_EQ(
r()->error(),
R"(12:34 error: runtime-sized arrays can only be used in the <storage> storage class
12:34 note: while instantiating parameter a)");
}
TEST_F(ResolverTypeValidationTest, AliasRuntimeArrayIsNotLast_Fail) {

View File

@ -262,13 +262,17 @@ TEST_F(ResolverVarLetValidationTest, NonConstructibleType_Atomic) {
}
TEST_F(ResolverVarLetValidationTest, NonConstructibleType_RuntimeArray) {
auto* s = Structure("S", {Member("m", ty.array(ty.i32()))}, {StructBlock()});
auto* v = Var("v", ty.Of(s));
auto* s = Structure("S", {Member(Source{{56, 78}}, "m", ty.array(ty.i32()))},
{StructBlock()});
auto* v = Var(Source{{12, 34}}, "v", ty.Of(s));
WrapInFunction(v);
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
"error: function variable must have a constructible type");
EXPECT_EQ(
r()->error(),
R"(12:34 error: runtime-sized arrays can only be used in the <storage> storage class
56:78 note: while analysing structure member S.m
12:34 note: while instantiating variable v)");
}
TEST_F(ResolverVarLetValidationTest, NonConstructibleType_Struct_WithAtomic) {