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>
diff --git a/src/resolver/resolver.cc b/src/resolver/resolver.cc
index e018a56..e346ed3 100644
--- a/src/resolver/resolver.cc
+++ b/src/resolver/resolver.cc
@@ -2650,6 +2650,14 @@
}
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);
}
diff --git a/src/resolver/resolver_validation.cc b/src/resolver/resolver_validation.cc
index 5a375aa..12e3b34 100644
--- a/src/resolver/resolver_validation.cc
+++ b/src/resolver/resolver_validation.cc
@@ -571,19 +571,6 @@
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:
diff --git a/src/resolver/storage_class_validation_test.cc b/src/resolver/storage_class_validation_test.cc
index 4c6799f..f836088 100644
--- a/src/resolver/storage_class_validation_test.cc
+++ b/src/resolver/storage_class_validation_test.cc
@@ -45,6 +45,52 @@
"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 @@
});
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) {
diff --git a/src/resolver/type_validation_test.cc b/src/resolver/type_validation_test.cc
index 2592246..08f37be 100644
--- a/src/resolver/type_validation_test.cc
+++ b/src/resolver/type_validation_test.cc
@@ -411,9 +411,10 @@
});
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 @@
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 @@
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 @@
});
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) {
diff --git a/src/resolver/var_let_validation_test.cc b/src/resolver/var_let_validation_test.cc
index bc0377a..9ee07b0 100644
--- a/src/resolver/var_let_validation_test.cc
+++ b/src/resolver/var_let_validation_test.cc
@@ -262,13 +262,17 @@
}
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) {