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) {