Resolver: Validate array el is not [[block]] struct
Fixed: tint:90
Change-Id: I9500a8c7fad9acf5f797dd2903217821c953acb6
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/48421
Commit-Queue: Ben Clayton <bclayton@google.com>
Auto-Submit: Ben Clayton <bclayton@google.com>
Reviewed-by: James Price <jrprice@google.com>
diff --git a/src/resolver/decoration_validation_test.cc b/src/resolver/decoration_validation_test.cc
index a927c46..5e9c5dc 100644
--- a/src/resolver/decoration_validation_test.cc
+++ b/src/resolver/decoration_validation_test.cc
@@ -438,5 +438,25 @@
} // namespace
} // namespace ArrayStrideTests
+
+namespace StructBlockTests {
+namespace {
+
+using StructBlockTest = ResolverTest;
+TEST_F(StructBlockTest, StructUsedAsArrayElement) {
+ auto* s = Structure("S", {Member("x", ty.i32())},
+ {create<ast::StructBlockDecoration>()});
+ auto* a = ty.array(s, 4);
+ Global("G", a, ast::StorageClass::kPrivate);
+
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_EQ(r()->error(),
+ "error: A structure type with a [[block]] decoration cannot be "
+ "used as an element of an array");
+}
+
+} // namespace
+} // namespace StructBlockTests
+
} // namespace resolver
} // namespace tint
diff --git a/src/resolver/resolver.cc b/src/resolver/resolver.cc
index e5bf012..084fe7c 100644
--- a/src/resolver/resolver.cc
+++ b/src/resolver/resolver.cc
@@ -2110,16 +2110,12 @@
return sem;
}
- // First check the element type is legal
- auto* el_ty = arr->type();
- if (!IsStorable(el_ty)) {
- builder_->Diagnostics().add_error(
- el_ty->FriendlyName(builder_->Symbols()) +
- " cannot be used as an element type of an array",
- source);
+ if (!ValidateArray(arr, source)) {
return nullptr;
}
+ auto* el_ty = arr->type();
+
uint32_t el_align = 0;
uint32_t el_size = 0;
if (!DefaultAlignAndSize(el_ty, el_align, el_size, source)) {
@@ -2147,19 +2143,7 @@
return nullptr;
}
explicit_stride = stride->stride();
- bool is_valid_stride = (explicit_stride >= el_size) &&
- (explicit_stride >= el_align) &&
- (explicit_stride % el_align == 0);
- if (!is_valid_stride) {
- // https://gpuweb.github.io/gpuweb/wgsl/#array-layout-rules
- // Arrays decorated with the stride attribute must have a stride that is
- // at least the size of the element type, and be a multiple of the
- // element type's alignment value.
- diagnostics_.add_error(
- "arrays decorated with the stride attribute must have a stride "
- "that is at least the size of the element type, and be a multiple "
- "of the element type's alignment value.",
- source);
+ if (!ValidateArrayStrideDecoration(stride, el_size, el_align, source)) {
return nullptr;
}
}
@@ -2173,6 +2157,55 @@
return create_semantic(implicit_stride);
}
+bool Resolver::ValidateArray(const sem::ArrayType* arr, const Source& source) {
+ auto* el_ty = arr->type();
+
+ if (!IsStorable(el_ty)) {
+ builder_->Diagnostics().add_error(
+ el_ty->FriendlyName(builder_->Symbols()) +
+ " cannot be used as an element type of an array",
+ source);
+ return false;
+ }
+
+ if (auto* el_str = el_ty->As<sem::StructType>()) {
+ if (el_str->impl()->IsBlockDecorated()) {
+ // https://gpuweb.github.io/gpuweb/wgsl/#attributes
+ // A structure type with the block attribute must not be:
+ // * the element type of an array type
+ // * the member type in another structure
+ diagnostics_.add_error(
+ "A structure type with a [[block]] decoration cannot be used as an "
+ "element of an array",
+ source);
+ return false;
+ }
+ }
+ return true;
+}
+
+bool Resolver::ValidateArrayStrideDecoration(const ast::StrideDecoration* deco,
+ uint32_t el_size,
+ uint32_t el_align,
+ const Source& source) {
+ auto stride = deco->stride();
+ bool is_valid_stride =
+ (stride >= el_size) && (stride >= el_align) && (stride % el_align == 0);
+ if (!is_valid_stride) {
+ // https://gpuweb.github.io/gpuweb/wgsl/#array-layout-rules
+ // Arrays decorated with the stride attribute must have a stride that is
+ // at least the size of the element type, and be a multiple of the
+ // element type's alignment value.
+ diagnostics_.add_error(
+ "arrays decorated with the stride attribute must have a stride "
+ "that is at least the size of the element type, and be a multiple "
+ "of the element type's alignment value.",
+ source);
+ return false;
+ }
+ return true;
+}
+
bool Resolver::ValidateStructure(const sem::StructType* st) {
for (auto* member : st->impl()->members()) {
if (auto* r = member->type()->UnwrapAll()->As<sem::ArrayType>()) {
diff --git a/src/resolver/resolver.h b/src/resolver/resolver.h
index f0aef7d..fc5f44f 100644
--- a/src/resolver/resolver.h
+++ b/src/resolver/resolver.h
@@ -236,6 +236,11 @@
// AST and Type validation methods
// Each return true on success, false on failure.
+ bool ValidateArray(const sem::ArrayType* arr, const Source& source);
+ bool ValidateArrayStrideDecoration(const ast::StrideDecoration* deco,
+ uint32_t el_size,
+ uint32_t el_align,
+ const Source& source);
bool ValidateAssignment(const ast::AssignmentStatement* a);
bool ValidateBinary(ast::BinaryExpression* expr);
bool ValidateEntryPoint(const ast::Function* func, const FunctionInfo* info);
diff --git a/test/compute_boids.wgsl b/test/compute_boids.wgsl
index e68daae..2f168dc 100644
--- a/test/compute_boids.wgsl
+++ b/test/compute_boids.wgsl
@@ -34,7 +34,7 @@
}
// compute shader
-[[block]] struct Particle {
+struct Particle {
pos : vec2<f32>;
vel : vec2<f32>;
};