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 (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( return ApplyStorageClassUsageToType(
sc, const_cast<sem::Type*>(arr->ElemType()), usage); sc, const_cast<sem::Type*>(arr->ElemType()), usage);
} }

View File

@ -571,19 +571,6 @@ bool Resolver::ValidateGlobalVariable(const sem::Variable* var) {
decl->source); decl->source);
return false; 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; break;
} }
default: default:

View File

@ -45,6 +45,52 @@ TEST_F(ResolverStorageClassValidationTest,
"the function storage class"); "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) { TEST_F(ResolverStorageClassValidationTest, StorageBufferBool) {
// var<storage> g : i32; // var<storage> g : i32;
Global(Source{{56, 78}}, "g", ty.i32(), ast::StorageClass::kStorage, Global(Source{{56, 78}}, "g", ty.i32(), ast::StorageClass::kStorage,
@ -170,9 +216,11 @@ TEST_F(ResolverStorageClassValidationTest, UniformBuffer_Struct_Runtime) {
}); });
ASSERT_FALSE(r()->Resolve()); ASSERT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(), EXPECT_EQ(
"56:78 error: structure containing a runtime sized array cannot be " r()->error(),
"used as a uniform buffer\n12:34 note: structure is declared here"); 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) { TEST_F(ResolverStorageClassValidationTest, UniformBufferBool) {

View File

@ -411,9 +411,10 @@ TEST_F(ResolverTypeValidationTest, RuntimeArrayInFunction_Fail) {
}); });
EXPECT_FALSE(r()->Resolve()); EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(), EXPECT_EQ(
"12:34 error: runtime arrays may only appear as the last member of " r()->error(),
"a struct"); 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) { TEST_F(ResolverTypeValidationTest, Struct_Member_VectorNoType) {
@ -575,7 +576,8 @@ TEST_F(ResolverTypeValidationTest, RuntimeArrayAsGlobalVariable) {
EXPECT_EQ( EXPECT_EQ(
r()->error(), 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) { TEST_F(ResolverTypeValidationTest, RuntimeArrayAsLocalVariable) {
@ -586,7 +588,8 @@ TEST_F(ResolverTypeValidationTest, RuntimeArrayAsLocalVariable) {
EXPECT_EQ( EXPECT_EQ(
r()->error(), 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) { TEST_F(ResolverTypeValidationTest, RuntimeArrayAsParameter_Fail) {
@ -610,9 +613,30 @@ TEST_F(ResolverTypeValidationTest, RuntimeArrayAsParameter_Fail) {
}); });
EXPECT_FALSE(r()->Resolve()) << r()->error(); EXPECT_FALSE(r()->Resolve()) << r()->error();
EXPECT_EQ(r()->error(), EXPECT_EQ(
"12:34 error: runtime arrays may only appear as the last member of " r()->error(),
"a struct"); 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) { TEST_F(ResolverTypeValidationTest, AliasRuntimeArrayIsNotLast_Fail) {

View File

@ -262,13 +262,17 @@ TEST_F(ResolverVarLetValidationTest, NonConstructibleType_Atomic) {
} }
TEST_F(ResolverVarLetValidationTest, NonConstructibleType_RuntimeArray) { TEST_F(ResolverVarLetValidationTest, NonConstructibleType_RuntimeArray) {
auto* s = Structure("S", {Member("m", ty.array(ty.i32()))}, {StructBlock()}); auto* s = Structure("S", {Member(Source{{56, 78}}, "m", ty.array(ty.i32()))},
auto* v = Var("v", ty.Of(s)); {StructBlock()});
auto* v = Var(Source{{12, 34}}, "v", ty.Of(s));
WrapInFunction(v); WrapInFunction(v);
EXPECT_FALSE(r()->Resolve()); EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(), EXPECT_EQ(
"error: function variable must have a constructible type"); 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) { TEST_F(ResolverVarLetValidationTest, NonConstructibleType_Struct_WithAtomic) {