validation: disallow non-constructible assignments The storage type of an assignment has to be constructible, which prevents stores to atomic or runtime-sized array types. Change-Id: Ie7bb703bb4c6953a4ddf0286f39d0d3e17b5b1d2 Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/61801 Kokoro: Kokoro <noreply+kokoro@google.com> Auto-Submit: James Price <jrprice@google.com> Reviewed-by: Sarah Mashayekhi <sarahmashay@google.com>
diff --git a/src/resolver/assignment_validation_test.cc b/src/resolver/assignment_validation_test.cc index 0e0ad42..580e552 100644 --- a/src/resolver/assignment_validation_test.cc +++ b/src/resolver/assignment_validation_test.cc
@@ -177,7 +177,7 @@ "12:34 error: cannot assign to const\nnote: 'a' is declared here:"); } -TEST_F(ResolverAssignmentValidationTest, AssignNonStorable_Fail) { +TEST_F(ResolverAssignmentValidationTest, AssignNonConstructible_Handle) { // var a : texture_storage_1d<rgba8unorm, read>; // var b : texture_storage_1d<rgba8unorm, read>; // a = b; @@ -203,8 +203,51 @@ EXPECT_FALSE(r()->Resolve()); EXPECT_EQ(r()->error(), - "56:78 error: cannot store into a read-only type " - "'texture_storage_1d<rgba8unorm, read>'"); + "56:78 error: storage type of assignment must be constructible"); +} + +TEST_F(ResolverAssignmentValidationTest, AssignNonConstructible_Atomic) { + // [[block]] struct S { a : atomic<i32>; }; + // [[group(0), binding(0)]] var<storage, read_write> v : S; + // v.a = v.a; + + auto* s = Structure("S", {Member("a", ty.atomic(ty.i32()))}, + {create<ast::StructBlockDecoration>()}); + Global(Source{{12, 34}}, "v", ty.Of(s), ast::StorageClass::kStorage, + ast::Access::kReadWrite, + ast::DecorationList{ + create<ast::BindingDecoration>(0), + create<ast::GroupDecoration>(0), + }); + + WrapInFunction(Assign(Source{{56, 78}}, MemberAccessor("v", "a"), + MemberAccessor("v", "a"))); + + EXPECT_FALSE(r()->Resolve()); + EXPECT_EQ(r()->error(), + "56:78 error: storage type of assignment must be constructible"); +} + +TEST_F(ResolverAssignmentValidationTest, AssignNonConstructible_RuntimeArray) { + // [[block]] struct S { a : array<f32>; }; + // [[group(0), binding(0)]] var<storage, read_write> v : S; + // v.a = v.a; + + auto* s = Structure("S", {Member("a", ty.array(ty.f32()))}, + {create<ast::StructBlockDecoration>()}); + Global(Source{{12, 34}}, "v", ty.Of(s), ast::StorageClass::kStorage, + ast::Access::kReadWrite, + ast::DecorationList{ + create<ast::BindingDecoration>(0), + create<ast::GroupDecoration>(0), + }); + + WrapInFunction(Assign(Source{{56, 78}}, MemberAccessor("v", "a"), + MemberAccessor("v", "a"))); + + EXPECT_FALSE(r()->Resolve()); + EXPECT_EQ(r()->error(), + "56:78 error: storage type of assignment must be constructible"); } } // namespace
diff --git a/src/resolver/resolver.cc b/src/resolver/resolver.cc index b8fca54..be8e45a 100644 --- a/src/resolver/resolver.cc +++ b/src/resolver/resolver.cc
@@ -4330,6 +4330,10 @@ a->source()); return false; } + if (!storage_type->IsConstructible()) { + AddError("storage type of assignment must be constructible", a->source()); + return false; + } if (lhs_ref->Access() == ast::Access::kRead) { AddError( "cannot store into a read-only type '" + TypeNameOf(a->lhs()) + "'",