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:
parent
13c79bef23
commit
db2f5fcf10
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
Loading…
Reference in New Issue