[wgsl-reader][wgsl-writer] Update struct decorations to new syntax.

This CL updates the parsing of struct decorations to require ()'s around
parameters.

Bug: tint:238
Change-Id: Ia35ca5c260c3c57b5fc95788bd1aef07f75edc39
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/28600
Reviewed-by: Sarah Mashayekhi <sarahmashay@google.com>
Commit-Queue: Sarah Mashayekhi <sarahmashay@google.com>
diff --git a/src/reader/wgsl/parser_impl.cc b/src/reader/wgsl/parser_impl.cc
index a85f7c7..5781a79 100644
--- a/src/reader/wgsl/parser_impl.cc
+++ b/src/reader/wgsl/parser_impl.cc
@@ -1641,7 +1641,7 @@
 }
 
 // struct_member_decoration
-//   : OFFSET INT_LITERAL
+//   : OFFSET PAREN_LEFT INT_LITERAL PAREN_RIGHT
 std::unique_ptr<ast::StructMemberDecoration>
 ParserImpl::struct_member_decoration() {
   auto t = peek();
@@ -1651,6 +1651,12 @@
   next();  // Consume the peek
 
   t = next();
+  if (!t.IsParenLeft()) {
+    set_error(t, "missing ( for offset");
+    return nullptr;
+  }
+
+  t = next();
   if (!t.IsSintLiteral()) {
     set_error(t, "invalid value for offset decoration");
     return nullptr;
@@ -1661,6 +1667,12 @@
     return nullptr;
   }
 
+  t = next();
+  if (!t.IsParenRight()) {
+    set_error(t, "missing ) for offset");
+    return nullptr;
+  }
+
   return std::make_unique<ast::StructMemberOffsetDecoration>(val);
 }
 
diff --git a/src/reader/wgsl/parser_impl_struct_body_decl_test.cc b/src/reader/wgsl/parser_impl_struct_body_decl_test.cc
index ecf29a9..93d0975 100644
--- a/src/reader/wgsl/parser_impl_struct_body_decl_test.cc
+++ b/src/reader/wgsl/parser_impl_struct_body_decl_test.cc
@@ -47,7 +47,7 @@
 TEST_F(ParserImplTest, StructBodyDecl_InvalidMember) {
   auto* p = parser(R"(
 {
-  [[offset nan]] a : i32;
+  [[offset(nan)]] a : i32;
 })");
   auto m = p->struct_body_decl();
   ASSERT_TRUE(p->has_error());
diff --git a/src/reader/wgsl/parser_impl_struct_decl_test.cc b/src/reader/wgsl/parser_impl_struct_decl_test.cc
index bb91899..b1480e1 100644
--- a/src/reader/wgsl/parser_impl_struct_decl_test.cc
+++ b/src/reader/wgsl/parser_impl_struct_decl_test.cc
@@ -26,7 +26,7 @@
   auto* p = parser(R"(
 struct {
   a : i32;
-  [[offset 4 ]] b : f32;
+  [[offset(4)]] b : f32;
 })");
   auto s = p->struct_decl();
   ASSERT_FALSE(p->has_error());
diff --git a/src/reader/wgsl/parser_impl_struct_member_decoration_decl_test.cc b/src/reader/wgsl/parser_impl_struct_member_decoration_decl_test.cc
index ea54e9c..9f57e0e 100644
--- a/src/reader/wgsl/parser_impl_struct_member_decoration_decl_test.cc
+++ b/src/reader/wgsl/parser_impl_struct_member_decoration_decl_test.cc
@@ -37,7 +37,7 @@
 }
 
 TEST_F(ParserImplTest, StructMemberDecorationDecl_Single) {
-  auto* p = parser("[[offset 4]]");
+  auto* p = parser("[[offset(4)]]");
   auto deco = p->struct_member_decoration_decl();
   ASSERT_FALSE(p->has_error());
   ASSERT_EQ(deco.size(), 1u);
@@ -45,24 +45,24 @@
 }
 
 TEST_F(ParserImplTest, StructMemberDecorationDecl_HandlesDuplicate) {
-  auto* p = parser("[[offset 2, offset 4]]");
+  auto* p = parser("[[offset(2), offset(4)]]");
   auto deco = p->struct_member_decoration_decl();
   ASSERT_TRUE(p->has_error()) << p->error();
-  EXPECT_EQ(p->error(), "1:21: duplicate offset decoration found");
+  EXPECT_EQ(p->error(), "1:23: duplicate offset decoration found");
 }
 
 TEST_F(ParserImplTest, StructMemberDecorationDecl_InvalidDecoration) {
-  auto* p = parser("[[offset nan]]");
+  auto* p = parser("[[offset(nan)]]");
   auto deco = p->struct_member_decoration_decl();
   ASSERT_TRUE(p->has_error()) << p->error();
   EXPECT_EQ(p->error(), "1:10: invalid value for offset decoration");
 }
 
 TEST_F(ParserImplTest, StructMemberDecorationDecl_MissingClose) {
-  auto* p = parser("[[offset 4");
+  auto* p = parser("[[offset(4)");
   auto deco = p->struct_member_decoration_decl();
   ASSERT_TRUE(p->has_error()) << p->error();
-  EXPECT_EQ(p->error(), "1:11: missing ]] for struct member decoration");
+  EXPECT_EQ(p->error(), "1:12: missing ]] for struct member decoration");
 }
 
 }  // namespace
diff --git a/src/reader/wgsl/parser_impl_struct_member_decoration_test.cc b/src/reader/wgsl/parser_impl_struct_member_decoration_test.cc
index 7be4bce..c01be53 100644
--- a/src/reader/wgsl/parser_impl_struct_member_decoration_test.cc
+++ b/src/reader/wgsl/parser_impl_struct_member_decoration_test.cc
@@ -23,7 +23,7 @@
 namespace {
 
 TEST_F(ParserImplTest, StructMemberDecoration_Offset) {
-  auto* p = parser("offset 4");
+  auto* p = parser("offset(4)");
   auto deco = p->struct_member_decoration();
   ASSERT_NE(deco, nullptr);
   ASSERT_FALSE(p->has_error());
@@ -33,16 +33,32 @@
   EXPECT_EQ(o->offset(), 4u);
 }
 
-TEST_F(ParserImplTest, StructMemberDecoration_Offset_MissingValue) {
-  auto* p = parser("offset");
+TEST_F(ParserImplTest, StructMemberDecoration_Offset_MissingLeftParen) {
+  auto* p = parser("offset 4)");
   auto deco = p->struct_member_decoration();
   ASSERT_EQ(deco, nullptr);
   ASSERT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:7: invalid value for offset decoration");
+  EXPECT_EQ(p->error(), "1:8: missing ( for offset");
+}
+
+TEST_F(ParserImplTest, StructMemberDecoration_Offset_MissingRightParen) {
+  auto* p = parser("offset(4");
+  auto deco = p->struct_member_decoration();
+  ASSERT_EQ(deco, nullptr);
+  ASSERT_TRUE(p->has_error());
+  EXPECT_EQ(p->error(), "1:9: missing ) for offset");
+}
+
+TEST_F(ParserImplTest, StructMemberDecoration_Offset_MissingValue) {
+  auto* p = parser("offset()");
+  auto deco = p->struct_member_decoration();
+  ASSERT_EQ(deco, nullptr);
+  ASSERT_TRUE(p->has_error());
+  EXPECT_EQ(p->error(), "1:8: invalid value for offset decoration");
 }
 
 TEST_F(ParserImplTest, StructMemberDecoration_Offset_MissingInvalid) {
-  auto* p = parser("offset nan");
+  auto* p = parser("offset(nan)");
   auto deco = p->struct_member_decoration();
   ASSERT_EQ(deco, nullptr);
   ASSERT_TRUE(p->has_error());
diff --git a/src/reader/wgsl/parser_impl_struct_member_test.cc b/src/reader/wgsl/parser_impl_struct_member_test.cc
index 49bc44c..7efe135 100644
--- a/src/reader/wgsl/parser_impl_struct_member_test.cc
+++ b/src/reader/wgsl/parser_impl_struct_member_test.cc
@@ -40,7 +40,7 @@
 TEST_F(ParserImplTest, StructMember_ParsesWithDecoration) {
   auto* i32 = tm()->Get(std::make_unique<ast::type::I32Type>());
 
-  auto* p = parser("[[offset 2]] a : i32;");
+  auto* p = parser("[[offset(2)]] a : i32;");
   auto m = p->struct_member();
   ASSERT_FALSE(p->has_error());
   ASSERT_NE(m, nullptr);
@@ -53,7 +53,7 @@
 }
 
 TEST_F(ParserImplTest, StructMember_InvalidDecoration) {
-  auto* p = parser("[[offset nan]] a : i32;");
+  auto* p = parser("[[offset(nan)]] a : i32;");
   auto m = p->struct_member();
   ASSERT_TRUE(p->has_error());
   ASSERT_EQ(m, nullptr);
@@ -61,11 +61,11 @@
 }
 
 TEST_F(ParserImplTest, StructMember_InvalidVariable) {
-  auto* p = parser("[[offset 4]] a : B;");
+  auto* p = parser("[[offset(4)]] a : B;");
   auto m = p->struct_member();
   ASSERT_TRUE(p->has_error());
   ASSERT_EQ(m, nullptr);
-  EXPECT_EQ(p->error(), "1:18: unknown type alias 'B'");
+  EXPECT_EQ(p->error(), "1:19: unknown type alias 'B'");
 }
 
 TEST_F(ParserImplTest, StructMember_MissingSemicolon) {
diff --git a/src/reader/wgsl/parser_impl_type_alias_test.cc b/src/reader/wgsl/parser_impl_type_alias_test.cc
index 2995881..d60360b 100644
--- a/src/reader/wgsl/parser_impl_type_alias_test.cc
+++ b/src/reader/wgsl/parser_impl_type_alias_test.cc
@@ -91,7 +91,8 @@
 
 TEST_F(ParserImplTest, TypeDecl_Struct_WithStride) {
   auto* p = parser(
-      "type a = [[block]] struct { [[offset 0]] data: [[stride 4]] array<f32>; "
+      "type a = [[block]] struct { [[offset(0)]] data: [[stride 4]] "
+      "array<f32>; "
       "}");
   auto* t = p->type_alias();
   ASSERT_FALSE(p->has_error());
diff --git a/src/writer/hlsl/generator_impl_member_accessor_test.cc b/src/writer/hlsl/generator_impl_member_accessor_test.cc
index 748b783..8f75a4a 100644
--- a/src/writer/hlsl/generator_impl_member_accessor_test.cc
+++ b/src/writer/hlsl/generator_impl_member_accessor_test.cc
@@ -80,8 +80,8 @@
 TEST_F(HlslGeneratorImplTest_MemberAccessor,
        EmitExpression_MemberAccessor_StorageBuffer_Load) {
   // struct Data {
-  //   [[offset 0]] a : i32;
-  //   [[offset 4]] b : f32;
+  //   [[offset(0)]] a : i32;
+  //   [[offset(4)]] b : f32;
   // };
   // var<storage_buffer> data : Data;
   // data.b;
@@ -129,8 +129,8 @@
 TEST_F(HlslGeneratorImplTest_MemberAccessor,
        EmitExpression_MemberAccessor_StorageBuffer_Load_Int) {
   // struct Data {
-  //   [[offset 0]] a : i32;
-  //   [[offset 4]] b : f32;
+  //   [[offset(0)]] a : i32;
+  //   [[offset(4)]] b : f32;
   // };
   // var<storage_buffer> data : Data;
   // data.a;
@@ -177,8 +177,8 @@
 TEST_F(HlslGeneratorImplTest_MemberAccessor,
        EmitExpression_MemberAccessor_StorageBuffer_Store_Matrix) {
   // struct Data {
-  //   [[offset 0]] z : f32;
-  //   [[offset 4]] a : mat2x3<f32>;
+  //   [[offset(0)]] z : f32;
+  //   [[offset(4)]] a : mat2x3<f32>;
   // };
   // var<storage_buffer> data : Data;
   // mat2x3<f32> b;
@@ -241,8 +241,8 @@
 TEST_F(HlslGeneratorImplTest_MemberAccessor,
        EmitExpression_MemberAccessor_StorageBuffer_Store_Matrix_Empty) {
   // struct Data {
-  //   [[offset 0]] z : f32;
-  //   [[offset 4]] a : mat2x3<f32>;
+  //   [[offset(0)]] z : f32;
+  //   [[offset(4)]] a : mat2x3<f32>;
   // };
   // var<storage_buffer> data : Data;
   // data.a = mat2x3<f32>();
@@ -303,8 +303,8 @@
 TEST_F(HlslGeneratorImplTest_MemberAccessor,
        EmitExpression_MemberAccessor_StorageBuffer_Load_Matrix) {
   // struct Data {
-  //   [[offset 0]] z : f32;
-  //   [[offset 4]] a : mat3x2<f32>;
+  //   [[offset(0)]] z : f32;
+  //   [[offset(4)]] a : mat3x2<f32>;
   // };
   // var<storage_buffer> data : Data;
   // data.a;
@@ -356,12 +356,12 @@
 TEST_F(HlslGeneratorImplTest_MemberAccessor,
        EmitExpression_MemberAccessor_StorageBuffer_Load_Matrix_Nested) {
   // struct Data {
-  //   [[offset 0]] z : f32;
-  //   [[offset 4]] a : mat2x3<f32;
+  //   [[offset(0)]] z : f32;
+  //   [[offset(4)]] a : mat2x3<f32;
   // };
   // struct Outer {
-  //   [[offset 0]] c : f32;
-  //   [[offset 4]] b : Data;
+  //   [[offset(0)]] c : f32;
+  //   [[offset(4)]] b : Data;
   // };
   // var<storage_buffer> data : Outer;
   // data.b.a;
@@ -413,7 +413,7 @@
     HlslGeneratorImplTest_MemberAccessor,
     EmitExpression_MemberAccessor_StorageBuffer_Load_Matrix_By3_Is_16_Bytes) {
   // struct Data {
-  //   [[offset 4]] a : mat3x3<f32;
+  //   [[offset(4)]] a : mat3x3<f32;
   // };
   // var<storage_buffer> data : Data;
   // data.a;
@@ -460,8 +460,8 @@
 TEST_F(HlslGeneratorImplTest_MemberAccessor,
        EmitExpression_MemberAccessor_StorageBuffer_Load_Matrix_Single_Element) {
   // struct Data {
-  //   [[offset 0]] z : f32;
-  //   [[offset 16]] a : mat4x3<f32>;
+  //   [[offset(0)]] z : f32;
+  //   [[offset(16)]] a : mat4x3<f32>;
   // };
   // var<storage_buffer> data : Data;
   // data.a[2][1];
@@ -516,7 +516,7 @@
 TEST_F(HlslGeneratorImplTest_MemberAccessor,
        EmitExpression_ArrayAccessor_StorageBuffer_Load_Int_FromArray) {
   // struct Data {
-  //   [[offset 0]] a : [[stride 4]] array<i32, 5>;
+  //   [[offset(0)]] a : [[stride 4]] array<i32, 5>;
   // };
   // var<storage_buffer> data : Data;
   // data.a[2];
@@ -564,7 +564,7 @@
 TEST_F(HlslGeneratorImplTest_MemberAccessor,
        EmitExpression_ArrayAccessor_StorageBuffer_Load_Int_FromArray_ExprIdx) {
   // struct Data {
-  //   [[offset 0]] a : [[stride 4]] array<i32, 5>;
+  //   [[offset(0)]] a : [[stride 4]] array<i32, 5>;
   // };
   // var<storage_buffer> data : Data;
   // data.a[(2 + 4) - 3];
@@ -620,8 +620,8 @@
 TEST_F(HlslGeneratorImplTest_MemberAccessor,
        EmitExpression_MemberAccessor_StorageBuffer_Store) {
   // struct Data {
-  //   [[offset 0]] a : i32;
-  //   [[offset 4]] b : f32;
+  //   [[offset(0)]] a : i32;
+  //   [[offset(4)]] b : f32;
   // };
   // var<storage_buffer> data : Data;
   // data.b = 2.3f;
@@ -674,7 +674,7 @@
 TEST_F(HlslGeneratorImplTest_MemberAccessor,
        EmitExpression_MemberAccessor_StorageBuffer_Store_ToArray) {
   // struct Data {
-  //   [[offset 0]] a : [[stride 4]] array<i32, 5>;
+  //   [[offset(0)]] a : [[stride 4]] array<i32, 5>;
   // };
   // var<storage_buffer> data : Data;
   // data.a[2] = 2;
@@ -727,8 +727,8 @@
 TEST_F(HlslGeneratorImplTest_MemberAccessor,
        EmitExpression_MemberAccessor_StorageBuffer_Store_Int) {
   // struct Data {
-  //   [[offset 0]] a : i32;
-  //   [[offset 4]] b : f32;
+  //   [[offset(0)]] a : i32;
+  //   [[offset(4)]] b : f32;
   // };
   // var<storage_buffer> data : Data;
   // data.a = 2;
@@ -781,8 +781,8 @@
 TEST_F(HlslGeneratorImplTest_MemberAccessor,
        EmitExpression_MemberAccessor_StorageBuffer_Load_Vec3) {
   // struct Data {
-  //   [[offset 0]] a : vec3<i32>;
-  //   [[offset 16]] b : vec3<f32>;
+  //   [[offset(0)]] a : vec3<i32>;
+  //   [[offset(16)]] b : vec3<f32>;
   // };
   // var<storage_buffer> data : Data;
   // data.b;
@@ -833,8 +833,8 @@
 TEST_F(HlslGeneratorImplTest_MemberAccessor,
        EmitExpression_MemberAccessor_StorageBuffer_Store_Vec3) {
   // struct Data {
-  //   [[offset 0]] a : vec3<i32>;
-  //   [[offset 16]] b : vec3<f32>;
+  //   [[offset(0)]] a : vec3<i32>;
+  //   [[offset(16)]] b : vec3<f32>;
   // };
   // var<storage_buffer> data : Data;
   // data.b = vec3<f32>(2.3f, 1.2f, 0.2f);
@@ -903,8 +903,8 @@
 TEST_F(HlslGeneratorImplTest_MemberAccessor,
        EmitExpression_MemberAccessor_StorageBuffer_Load_MultiLevel) {
   // struct Data {
-  //   [[offset 0]] a : vec3<i32>;
-  //   [[offset 16]] b : vec3<f32>;
+  //   [[offset(0)]] a : vec3<i32>;
+  //   [[offset(16)]] b : vec3<f32>;
   // };
   // struct Pre {
   //   var c : [[stride 32]] array<Data, 4>;
@@ -976,8 +976,8 @@
 TEST_F(HlslGeneratorImplTest_MemberAccessor,
        EmitExpression_MemberAccessor_StorageBuffer_Load_MultiLevel_Swizzle) {
   // struct Data {
-  //   [[offset 0]] a : vec3<i32>;
-  //   [[offset 16]] b : vec3<f32>;
+  //   [[offset(0)]] a : vec3<i32>;
+  //   [[offset(16)]] b : vec3<f32>;
   // };
   // struct Pre {
   //   var c : [[stride 32]] array<Data, 4>;
@@ -1052,8 +1052,8 @@
     HlslGeneratorImplTest_MemberAccessor,
     EmitExpression_MemberAccessor_StorageBuffer_Load_MultiLevel_Swizzle_SingleLetter) {
   // struct Data {
-  //   [[offset 0]] a : vec3<i32>;
-  //   [[offset 16]] b : vec3<f32>;
+  //   [[offset(0)]] a : vec3<i32>;
+  //   [[offset(16)]] b : vec3<f32>;
   // };
   // struct Pre {
   //   var c : [[stride 32]] array<Data, 4>;
@@ -1127,8 +1127,8 @@
 TEST_F(HlslGeneratorImplTest_MemberAccessor,
        EmitExpression_MemberAccessor_StorageBuffer_Load_MultiLevel_Index) {
   // struct Data {
-  //   [[offset 0]] a : vec3<i32>;
-  //   [[offset 16]] b : vec3<f32>;
+  //   [[offset(0)]] a : vec3<i32>;
+  //   [[offset(16)]] b : vec3<f32>;
   // };
   // struct Pre {
   //   var c : [[stride 32]] array<Data, 4>;
@@ -1203,8 +1203,8 @@
 TEST_F(HlslGeneratorImplTest_MemberAccessor,
        EmitExpression_MemberAccessor_StorageBuffer_Store_MultiLevel) {
   // struct Data {
-  //   [[offset 0]] a : vec3<i32>;
-  //   [[offset 16]] b : vec3<f32>;
+  //   [[offset(0)]] a : vec3<i32>;
+  //   [[offset(16)]] b : vec3<f32>;
   // };
   // struct Pre {
   //   var c : [[stride 32]] array<Data, 4>;
@@ -1295,8 +1295,8 @@
 TEST_F(HlslGeneratorImplTest_MemberAccessor,
        EmitExpression_MemberAccessor_StorageBuffer_Store_Swizzle_SingleLetter) {
   // struct Data {
-  //   [[offset 0]] a : vec3<i32>;
-  //   [[offset 16]] b : vec3<f32>;
+  //   [[offset(0)]] a : vec3<i32>;
+  //   [[offset(16)]] b : vec3<f32>;
   // };
   // struct Pre {
   //   var c : [[stride 32]] array<Data, 4>;
diff --git a/src/writer/wgsl/generator_impl.cc b/src/writer/wgsl/generator_impl.cc
index c64a1b3..d13d1bb 100644
--- a/src/writer/wgsl/generator_impl.cc
+++ b/src/writer/wgsl/generator_impl.cc
@@ -633,7 +633,7 @@
           // TODO(dsinclair): Split this out when we have more then one
           assert(deco->IsOffset());
 
-          out_ << "offset " << deco->AsOffset()->offset();
+          out_ << "offset(" << deco->AsOffset()->offset() << ")";
         }
         out_ << "]] ";
       }
diff --git a/src/writer/wgsl/generator_impl_alias_type_test.cc b/src/writer/wgsl/generator_impl_alias_type_test.cc
index 8608f10..e0b04ff 100644
--- a/src/writer/wgsl/generator_impl_alias_type_test.cc
+++ b/src/writer/wgsl/generator_impl_alias_type_test.cc
@@ -62,7 +62,7 @@
   ASSERT_TRUE(g.EmitAliasType(&alias)) << g.error();
   EXPECT_EQ(g.result(), R"(type a = struct {
   a : f32;
-  [[offset 4]] b : i32;
+  [[offset(4)]] b : i32;
 };
 )");
 }
diff --git a/src/writer/wgsl/generator_impl_type_test.cc b/src/writer/wgsl/generator_impl_type_test.cc
index fe09925..05aade7 100644
--- a/src/writer/wgsl/generator_impl_type_test.cc
+++ b/src/writer/wgsl/generator_impl_type_test.cc
@@ -143,7 +143,7 @@
   ASSERT_TRUE(g.EmitType(&s)) << g.error();
   EXPECT_EQ(g.result(), R"(struct {
   a : i32;
-  [[offset 4]] b : f32;
+  [[offset(4)]] b : f32;
 })");
 }
 
@@ -170,7 +170,7 @@
   ASSERT_TRUE(g.EmitType(&s)) << g.error();
   EXPECT_EQ(g.result(), R"([[block]] struct {
   a : i32;
-  [[offset 4]] b : f32;
+  [[offset(4)]] b : f32;
 })");
 }
 
diff --git a/test/compute_boids.wgsl b/test/compute_boids.wgsl
index 5752620..1cf7d3a 100644
--- a/test/compute_boids.wgsl
+++ b/test/compute_boids.wgsl
@@ -42,22 +42,22 @@
 
 # compute shader
 type Particle = [[block]] struct {
-  [[offset 0]] pos : vec2<f32>;
-  [[offset 8]] vel : vec2<f32>;
+  [[offset(0)]] pos : vec2<f32>;
+  [[offset(8)]] vel : vec2<f32>;
 };
 
 type SimParams = [[block]] struct {
-  [[offset 0]] deltaT : f32;
-  [[offset 4]] rule1Distance : f32;
-  [[offset 8]] rule2Distance : f32;
-  [[offset 12]] rule3Distance : f32;
-  [[offset 16]] rule1Scale : f32;
-  [[offset 20]] rule2Scale : f32;
-  [[offset 24]] rule3Scale : f32;
+  [[offset(0)]] deltaT : f32;
+  [[offset(4)]] rule1Distance : f32;
+  [[offset(8)]] rule2Distance : f32;
+  [[offset(12)]] rule3Distance : f32;
+  [[offset(16)]] rule1Scale : f32;
+  [[offset(20)]] rule2Scale : f32;
+  [[offset(24)]] rule3Scale : f32;
 };
 
 type Particles = [[block]] struct {
-  [[offset 0]] particles : [[stride 16]] array<Particle, 5>;
+  [[offset(0)]] particles : [[stride 16]] array<Particle, 5>;
 };
 
 [[binding 0, set 0]] var<uniform> params : SimParams;
diff --git a/test/cube.wgsl b/test/cube.wgsl
index 88dbd64..7ed1b2c 100644
--- a/test/cube.wgsl
+++ b/test/cube.wgsl
@@ -17,7 +17,7 @@
 
 # Vertex shader
 type Uniforms = [[block]] struct {
-  [[offset 0]] modelViewProjectionMatrix : mat4x4<f32>;
+  [[offset(0)]] modelViewProjectionMatrix : mat4x4<f32>;
 };
 
 [[binding 0, set 0]] var<uniform> uniforms : Uniforms;