PB: Make Var() and Global() params optional

and allow them in any order.

We're about to add Yet Another optional parameter - access control.
For style, we probably want this field before the decorations, however
that means adding more default values for all the cases where we don't
need to specify the access control.

Instead use some template magic to allow extra parameters to be
specified in any order, and entirely optional, with sensible defaults.
This keeps things readable and without huge code refactorings.

Bug: tint:846
Change-Id: I4f61eb765de63ad98ae786d187d2bd1b42942756
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/53087
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: Antonio Maiorano <amaiorano@google.com>
Commit-Queue: Ben Clayton <bclayton@google.com>
diff --git a/src/program_builder.cc b/src/program_builder.cc
index 0f76194..a85ba4d 100644
--- a/src/program_builder.cc
+++ b/src/program_builder.cc
@@ -24,6 +24,8 @@
 
 namespace tint {
 
+ProgramBuilder::VarOptionals::~VarOptionals() = default;
+
 ProgramBuilder::ProgramBuilder()
     : id_(ProgramID::New()),
       ast_(ast_nodes_.Create<ast::Module>(id_, Source{})) {}
diff --git a/src/program_builder.h b/src/program_builder.h
index 3a102ff..5319a13 100644
--- a/src/program_builder.h
+++ b/src/program_builder.h
@@ -91,6 +91,32 @@
 /// To construct a Program, populate the builder and then `std::move` it to a
 /// Program.
 class ProgramBuilder {
+  /// VarOptionals is a helper for accepting a number of optional, extra
+  /// arguments for Var() and Global().
+  struct VarOptionals {
+    template <typename... ARGS>
+    explicit VarOptionals(ARGS&&... args) {
+      Apply(std::forward<ARGS>(args)...);
+    }
+    ~VarOptionals();
+
+    ast::StorageClass storage = ast::StorageClass::kNone;
+    ast::Expression* constructor = nullptr;
+    ast::DecorationList decorations = {};
+
+   private:
+    void Set(ast::StorageClass sc) { storage = sc; }
+    void Set(ast::Expression* c) { constructor = c; }
+    void Set(const ast::DecorationList& l) { decorations = l; }
+
+    template <typename FIRST, typename... ARGS>
+    void Apply(FIRST&& first, ARGS&&... args) {
+      Set(std::forward<FIRST>(first));
+      Apply(std::forward<ARGS>(args)...);
+    }
+    void Apply() {}
+  };
+
  public:
   /// ASTNodeAllocator is an alias to BlockAllocator<ast::Node>
   using ASTNodeAllocator = BlockAllocator<ast::Node>;
@@ -1187,38 +1213,47 @@
 
   /// @param name the variable name
   /// @param type the variable type
-  /// @param storage the variable storage class
-  /// @param constructor constructor expression
-  /// @param decorations variable decorations
-  /// @returns a `ast::Variable` with the given name, storage and type
-  template <typename NAME>
+  /// @param optional the optional variable settings.
+  /// Can be any of the following, in any order:
+  ///   * ast::StorageClass   - specifies the variable storage class
+  ///   * ast::Expression*    - specifies the variable's initializer expression
+  ///   * ast::DecorationList - specifies the variable's decorations
+  /// Note that repeated arguments of the same type will use the last argument's
+  /// value.
+  /// @returns a `ast::Variable` with the given name, type and additional
+  /// options
+  template <typename NAME, typename... OPTIONAL>
   ast::Variable* Var(NAME&& name,
                      const ast::Type* type,
-                     ast::StorageClass storage = ast::StorageClass::kNone,
-                     ast::Expression* constructor = nullptr,
-                     ast::DecorationList decorations = {}) {
+                     OPTIONAL&&... optional) {
     type = ty.MaybeCreateTypename(type);
-    return create<ast::Variable>(Sym(std::forward<NAME>(name)), storage, type,
-                                 false, constructor, decorations);
+    VarOptionals opts(std::forward<OPTIONAL>(optional)...);
+    return create<ast::Variable>(Sym(std::forward<NAME>(name)), opts.storage,
+                                 type, false, opts.constructor,
+                                 std::move(opts.decorations));
   }
 
   /// @param source the variable source
   /// @param name the variable name
   /// @param type the variable type
-  /// @param storage the variable storage class
-  /// @param constructor constructor expression
-  /// @param decorations variable decorations
+  /// @param optional the optional variable settings.
+  /// Can be any of the following, in any order:
+  ///   * ast::StorageClass   - specifies the variable storage class
+  ///   * ast::Expression*    - specifies the variable's initializer expression
+  ///   * ast::DecorationList - specifies the variable's decorations
+  /// Note that repeated arguments of the same type will use the last argument's
+  /// value.
   /// @returns a `ast::Variable` with the given name, storage and type
-  template <typename NAME>
+  template <typename NAME, typename... OPTIONAL>
   ast::Variable* Var(const Source& source,
                      NAME&& name,
                      const ast::Type* type,
-                     ast::StorageClass storage = ast::StorageClass::kNone,
-                     ast::Expression* constructor = nullptr,
-                     ast::DecorationList decorations = {}) {
+                     OPTIONAL&&... optional) {
     type = ty.MaybeCreateTypename(type);
-    return create<ast::Variable>(source, Sym(std::forward<NAME>(name)), storage,
-                                 type, false, constructor, decorations);
+    VarOptionals opts(std::forward<OPTIONAL>(optional)...);
+    return create<ast::Variable>(source, Sym(std::forward<NAME>(name)),
+                                 opts.storage, type, false, opts.constructor,
+                                 std::move(opts.decorations));
   }
 
   /// @param name the variable name
@@ -1287,19 +1322,21 @@
 
   /// @param name the variable name
   /// @param type the variable type
-  /// @param storage the variable storage class
-  /// @param constructor constructor expression
-  /// @param decorations variable decorations
+  /// @param optional the optional variable settings.
+  /// Can be any of the following, in any order:
+  ///   * ast::StorageClass   - specifies the variable storage class
+  ///   * ast::Expression*    - specifies the variable's initializer expression
+  ///   * ast::DecorationList - specifies the variable's decorations
+  /// Note that repeated arguments of the same type will use the last argument's
+  /// value.
   /// @returns a new `ast::Variable`, which is automatically registered as a
   /// global variable with the ast::Module.
-  template <typename NAME>
+  template <typename NAME, typename... OPTIONAL>
   ast::Variable* Global(NAME&& name,
                         const ast::Type* type,
-                        ast::StorageClass storage,
-                        ast::Expression* constructor = nullptr,
-                        ast::DecorationList decorations = {}) {
-    auto* var =
-        Var(std::forward<NAME>(name), type, storage, constructor, decorations);
+                        OPTIONAL&&... optional) {
+    auto* var = Var(std::forward<NAME>(name), type,
+                    std::forward<OPTIONAL>(optional)...);
     AST().AddGlobalVariable(var);
     return var;
   }
@@ -1307,20 +1344,22 @@
   /// @param source the variable source
   /// @param name the variable name
   /// @param type the variable type
-  /// @param storage the variable storage class
-  /// @param constructor constructor expression
-  /// @param decorations variable decorations
+  /// @param optional the optional variable settings.
+  /// Can be any of the following, in any order:
+  ///   * ast::StorageClass   - specifies the variable storage class
+  ///   * ast::Expression*    - specifies the variable's initializer expression
+  ///   * ast::DecorationList - specifies the variable's decorations
+  /// Note that repeated arguments of the same type will use the last argument's
+  /// value.
   /// @returns a new `ast::Variable`, which is automatically registered as a
   /// global variable with the ast::Module.
-  template <typename NAME>
+  template <typename NAME, typename... OPTIONAL>
   ast::Variable* Global(const Source& source,
                         NAME&& name,
                         ast::Type* type,
-                        ast::StorageClass storage,
-                        ast::Expression* constructor = nullptr,
-                        ast::DecorationList decorations = {}) {
-    auto* var = Var(source, std::forward<NAME>(name), type, storage,
-                    constructor, decorations);
+                        OPTIONAL&&... optional) {
+    auto* var = Var(source, std::forward<NAME>(name), type,
+                    std::forward<OPTIONAL>(optional)...);
     AST().AddGlobalVariable(var);
     return var;
   }
diff --git a/src/resolver/assignment_validation_test.cc b/src/resolver/assignment_validation_test.cc
index 62b7f6f..dab2610 100644
--- a/src/resolver/assignment_validation_test.cc
+++ b/src/resolver/assignment_validation_test.cc
@@ -136,8 +136,8 @@
   // let b : ptr<function,i32> = &a;
   // *b = 2;
   const auto func = ast::StorageClass::kFunction;
-  auto* var_a = Var("a", ty.i32(), func, Expr(2), {});
-  auto* var_b = Const("b", ty.pointer<int>(func), AddressOf(Expr("a")), {});
+  auto* var_a = Var("a", ty.i32(), func, Expr(2));
+  auto* var_b = Const("b", ty.pointer<int>(func), AddressOf(Expr("a")));
   WrapInFunction(var_a, var_b, Assign(Source{{12, 34}}, Deref("b"), 2));
 
   EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -166,13 +166,13 @@
     return ty.access(ast::AccessControl::kRead, tex_type);
   };
 
-  Global("a", make_type(), ast::StorageClass::kNone, nullptr,
-         {
+  Global("a", make_type(), ast::StorageClass::kNone,
+         ast::DecorationList{
              create<ast::BindingDecoration>(0),
              create<ast::GroupDecoration>(0),
          });
-  Global("b", make_type(), ast::StorageClass::kNone, nullptr,
-         {
+  Global("b", make_type(), ast::StorageClass::kNone,
+         ast::DecorationList{
              create<ast::BindingDecoration>(1),
              create<ast::GroupDecoration>(0),
          });
diff --git a/src/resolver/decoration_validation_test.cc b/src/resolver/decoration_validation_test.cc
index 4b6c77c..e24dc70 100644
--- a/src/resolver/decoration_validation_test.cc
+++ b/src/resolver/decoration_validation_test.cc
@@ -554,8 +554,8 @@
 
 TEST_F(ResourceDecorationTest, BindingPairMissingBinding) {
   Global(Source{{12, 34}}, "G", ty.sampler(ast::SamplerKind::kSampler),
-         ast::StorageClass::kNone, nullptr,
-         {
+         ast::StorageClass::kNone,
+         ast::DecorationList{
              create<ast::GroupDecoration>(1),
          });
 
@@ -567,8 +567,8 @@
 
 TEST_F(ResourceDecorationTest, BindingPairMissingGroup) {
   Global(Source{{12, 34}}, "G", ty.sampler(ast::SamplerKind::kSampler),
-         ast::StorageClass::kNone, nullptr,
-         {
+         ast::StorageClass::kNone,
+         ast::DecorationList{
              create<ast::BindingDecoration>(1),
          });
 
@@ -581,15 +581,15 @@
 TEST_F(ResourceDecorationTest, BindingPointUsedTwiceByEntryPoint) {
   Global(Source{{12, 34}}, "A",
          ty.sampled_texture(ast::TextureDimension::k2d, ty.f32()),
-         ast::StorageClass::kNone, nullptr,
-         {
+         ast::StorageClass::kNone,
+         ast::DecorationList{
              create<ast::BindingDecoration>(1),
              create<ast::GroupDecoration>(2),
          });
   Global(Source{{56, 78}}, "B",
          ty.sampled_texture(ast::TextureDimension::k2d, ty.f32()),
-         ast::StorageClass::kNone, nullptr,
-         {
+         ast::StorageClass::kNone,
+         ast::DecorationList{
              create<ast::BindingDecoration>(1),
              create<ast::GroupDecoration>(2),
          });
@@ -613,15 +613,15 @@
 TEST_F(ResourceDecorationTest, BindingPointUsedTwiceByDifferentEntryPoints) {
   Global(Source{{12, 34}}, "A",
          ty.sampled_texture(ast::TextureDimension::k2d, ty.f32()),
-         ast::StorageClass::kNone, nullptr,
-         {
+         ast::StorageClass::kNone,
+         ast::DecorationList{
              create<ast::BindingDecoration>(1),
              create<ast::GroupDecoration>(2),
          });
   Global(Source{{56, 78}}, "B",
          ty.sampled_texture(ast::TextureDimension::k2d, ty.f32()),
-         ast::StorageClass::kNone, nullptr,
-         {
+         ast::StorageClass::kNone,
+         ast::DecorationList{
              create<ast::BindingDecoration>(1),
              create<ast::GroupDecoration>(2),
          });
@@ -643,8 +643,8 @@
 }
 
 TEST_F(ResourceDecorationTest, BindingPointOnNonResource) {
-  Global(Source{{12, 34}}, "G", ty.f32(), ast::StorageClass::kPrivate, nullptr,
-         {
+  Global(Source{{12, 34}}, "G", ty.f32(), ast::StorageClass::kPrivate,
+         ast::DecorationList{
              create<ast::BindingDecoration>(1),
              create<ast::GroupDecoration>(2),
          });
diff --git a/src/resolver/host_shareable_validation_test.cc b/src/resolver/host_shareable_validation_test.cc
index 96fe861..bb73ad9 100644
--- a/src/resolver/host_shareable_validation_test.cc
+++ b/src/resolver/host_shareable_validation_test.cc
@@ -29,8 +29,8 @@
   auto* s = Structure("S", {Member(Source{{12, 34}}, "x", ty.bool_())},
                       {create<ast::StructBlockDecoration>()});
   auto* a = ty.access(ast::AccessControl::kRead, s);
-  Global(Source{{56, 78}}, "g", a, ast::StorageClass::kStorage, nullptr,
-         {
+  Global(Source{{56, 78}}, "g", a, ast::StorageClass::kStorage,
+         ast::DecorationList{
              create<ast::BindingDecoration>(0),
              create<ast::GroupDecoration>(0),
          });
@@ -48,8 +48,8 @@
   auto* s = Structure("S", {Member(Source{{12, 34}}, "x", ty.vec3<bool>())},
                       {create<ast::StructBlockDecoration>()});
   auto* a = ty.access(ast::AccessControl::kRead, s);
-  Global(Source{{56, 78}}, "g", a, ast::StorageClass::kStorage, nullptr,
-         {
+  Global(Source{{56, 78}}, "g", a, ast::StorageClass::kStorage,
+         ast::DecorationList{
              create<ast::BindingDecoration>(0),
              create<ast::GroupDecoration>(0),
          });
@@ -71,8 +71,8 @@
   auto* ac = ty.access(ast::AccessControl::kRead, s);
   auto* a2 = ty.alias("a2", ac);
   AST().AddConstructedType(a2);
-  Global(Source{{56, 78}}, "g", a2, ast::StorageClass::kStorage, nullptr,
-         {
+  Global(Source{{56, 78}}, "g", a2, ast::StorageClass::kStorage,
+         ast::DecorationList{
              create<ast::BindingDecoration>(0),
              create<ast::GroupDecoration>(0),
          });
@@ -94,8 +94,8 @@
   auto* s = Structure("S", {Member(Source{{7, 8}}, "m", i3)},
                       {create<ast::StructBlockDecoration>()});
   auto* a = ty.access(ast::AccessControl::kRead, s);
-  Global(Source{{9, 10}}, "g", a, ast::StorageClass::kStorage, nullptr,
-         {
+  Global(Source{{9, 10}}, "g", a, ast::StorageClass::kStorage,
+         ast::DecorationList{
              create<ast::BindingDecoration>(0),
              create<ast::GroupDecoration>(0),
          });
@@ -136,8 +136,8 @@
   auto* s = Structure("S", {Member(Source{{7, 8}}, "m", i3)},
                       {create<ast::StructBlockDecoration>()});
   auto* a = ty.access(ast::AccessControl::kRead, s);
-  Global(Source{{9, 10}}, "g", a, ast::StorageClass::kStorage, nullptr,
-         {
+  Global(Source{{9, 10}}, "g", a, ast::StorageClass::kStorage,
+         ast::DecorationList{
              create<ast::BindingDecoration>(0),
              create<ast::GroupDecoration>(0),
          });
diff --git a/src/resolver/intrinsic_test.cc b/src/resolver/intrinsic_test.cc
index ba8af09..701796f 100644
--- a/src/resolver/intrinsic_test.cc
+++ b/src/resolver/intrinsic_test.cc
@@ -245,8 +245,8 @@
                       const ast::Type* type,
                       ast::ExpressionList* call_params) {
     if (type->UnwrapAll()->is_handle()) {
-      Global(name, type, ast::StorageClass::kNone, nullptr,
-             {
+      Global(name, type,
+             ast::DecorationList{
                  create<ast::BindingDecoration>(0),
                  create<ast::GroupDecoration>(0),
              });
@@ -770,8 +770,8 @@
   auto* str = Structure("S", {Member("x", ary)},
                         {create<ast::StructBlockDecoration>()});
   auto* ac = ty.access(ast::AccessControl::kRead, str);
-  Global("a", ac, ast::StorageClass::kStorage, nullptr,
-         {
+  Global("a", ac, ast::StorageClass::kStorage,
+         ast::DecorationList{
              create<ast::BindingDecoration>(0),
              create<ast::GroupDecoration>(0),
          });
diff --git a/src/resolver/resolver_test.cc b/src/resolver/resolver_test.cc
index ef44748..84935c4 100644
--- a/src/resolver/resolver_test.cc
+++ b/src/resolver/resolver_test.cc
@@ -677,8 +677,8 @@
   auto* my_var_b = Expr("my_var");
   auto* assign = Assign(my_var_a, my_var_b);
 
-  auto* var = Var("my_var", ty.f32(), ast::StorageClass::kNone, nullptr,
-                  {
+  auto* var = Var("my_var", ty.f32(),
+                  ast::DecorationList{
                       create<ast::BindingDecoration>(0),
                       create<ast::GroupDecoration>(0),
                   });
@@ -788,8 +788,8 @@
 
   auto* in_var = Global("in_var", ty.f32(), ast::StorageClass::kInput);
   auto* out_var = Global("out_var", ty.f32(), ast::StorageClass::kOutput);
-  auto* sb_var = Global("sb_var", a, ast::StorageClass::kStorage, nullptr,
-                        {
+  auto* sb_var = Global("sb_var", a, ast::StorageClass::kStorage,
+                        ast::DecorationList{
                             create<ast::BindingDecoration>(0),
                             create<ast::GroupDecoration>(0),
                         });
@@ -827,8 +827,8 @@
 
   auto* in_var = Global("in_var", ty.f32(), ast::StorageClass::kInput);
   auto* out_var = Global("out_var", ty.f32(), ast::StorageClass::kOutput);
-  auto* sb_var = Global("sb_var", a, ast::StorageClass::kStorage, nullptr,
-                        {
+  auto* sb_var = Global("sb_var", a, ast::StorageClass::kStorage,
+                        ast::DecorationList{
                             create<ast::BindingDecoration>(0),
                             create<ast::GroupDecoration>(0),
                         });
@@ -1727,8 +1727,8 @@
                                          ast::UnaryOp::kNot));
 
 TEST_F(ResolverTest, StorageClass_SetsIfMissing) {
-  auto* var = Var("var", ty.i32(), ast::StorageClass::kNone, nullptr,
-                  {
+  auto* var = Var("var", ty.i32(),
+                  ast::DecorationList{
                       create<ast::BindingDecoration>(0),
                       create<ast::GroupDecoration>(0),
                   });
@@ -1743,8 +1743,8 @@
 
 TEST_F(ResolverTest, StorageClass_SetForSampler) {
   auto* t = ty.sampler(ast::SamplerKind::kSampler);
-  auto* var = Global("var", t, ast::StorageClass::kNone, nullptr,
-                     {
+  auto* var = Global("var", t,
+                     ast::DecorationList{
                          create<ast::BindingDecoration>(0),
                          create<ast::GroupDecoration>(0),
                      });
@@ -1758,8 +1758,8 @@
 TEST_F(ResolverTest, StorageClass_SetForTexture) {
   auto* t = ty.sampled_texture(ast::TextureDimension::k1d, ty.f32());
   auto* ac = ty.access(ast::AccessControl::kRead, t);
-  auto* var = Global("var", ac, ast::StorageClass::kNone, nullptr,
-                     {
+  auto* var = Global("var", ac,
+                     ast::DecorationList{
                          create<ast::BindingDecoration>(0),
                          create<ast::GroupDecoration>(0),
                      });
diff --git a/src/resolver/storage_class_validation_test.cc b/src/resolver/storage_class_validation_test.cc
index 95df0a7..67efdd7 100644
--- a/src/resolver/storage_class_validation_test.cc
+++ b/src/resolver/storage_class_validation_test.cc
@@ -36,8 +36,8 @@
 
 TEST_F(ResolverStorageClassValidationTest, StorageBufferBool) {
   // var<storage> g : i32;
-  Global(Source{{56, 78}}, "g", ty.i32(), ast::StorageClass::kStorage, nullptr,
-         {
+  Global(Source{{56, 78}}, "g", ty.i32(), ast::StorageClass::kStorage,
+         ast::DecorationList{
              create<ast::BindingDecoration>(0),
              create<ast::GroupDecoration>(0),
          });
@@ -52,8 +52,8 @@
 TEST_F(ResolverStorageClassValidationTest, StorageBufferPointer) {
   // var<storage> g : ptr<i32, input>;
   Global(Source{{56, 78}}, "g", ty.pointer<i32>(ast::StorageClass::kInput),
-         ast::StorageClass::kStorage, nullptr,
-         {
+         ast::StorageClass::kStorage,
+         ast::DecorationList{
              create<ast::BindingDecoration>(0),
              create<ast::GroupDecoration>(0),
          });
@@ -70,8 +70,8 @@
   auto* s = Structure("S", {Member("a", ty.f32())});
   auto* a = ty.array(s, 3);
   auto* ac = ty.access(ast::AccessControl::kRead, a);
-  Global(Source{{56, 78}}, "g", ac, ast::StorageClass::kStorage, nullptr,
-         {
+  Global(Source{{56, 78}}, "g", ac, ast::StorageClass::kStorage,
+         ast::DecorationList{
              create<ast::BindingDecoration>(0),
              create<ast::GroupDecoration>(0),
          });
@@ -88,8 +88,8 @@
   // var<storage> g : [[access(read)]] a;
   auto* a = ty.alias("a", ty.bool_());
   AST().AddConstructedType(a);
-  Global(Source{{56, 78}}, "g", a, ast::StorageClass::kStorage, nullptr,
-         {
+  Global(Source{{56, 78}}, "g", a, ast::StorageClass::kStorage,
+         ast::DecorationList{
              create<ast::BindingDecoration>(0),
              create<ast::GroupDecoration>(0),
          });
@@ -104,8 +104,8 @@
 TEST_F(ResolverStorageClassValidationTest, StorageBufferNoAccessControl) {
   // var<storage> g : S;
   auto* s = Structure("S", {Member(Source{{12, 34}}, "x", ty.i32())});
-  Global(Source{{56, 78}}, "g", s, ast::StorageClass::kStorage, nullptr,
-         {
+  Global(Source{{56, 78}}, "g", s, ast::StorageClass::kStorage,
+         ast::DecorationList{
              create<ast::BindingDecoration>(0),
              create<ast::GroupDecoration>(0),
          });
@@ -122,8 +122,8 @@
   // var<storage> g : [[access(read)]] S;
   auto* s = Structure(Source{{12, 34}}, "S", {Member("x", ty.i32())});
   auto* a = ty.access(ast::AccessControl::kRead, s);
-  Global(Source{{56, 78}}, "g", a, ast::StorageClass::kStorage, nullptr,
-         {
+  Global(Source{{56, 78}}, "g", a, ast::StorageClass::kStorage,
+         ast::DecorationList{
              create<ast::BindingDecoration>(0),
              create<ast::GroupDecoration>(0),
          });
@@ -142,8 +142,8 @@
   auto* s = Structure("S", {Member(Source{{12, 34}}, "x", ty.i32())},
                       {create<ast::StructBlockDecoration>()});
   auto* a = ty.access(ast::AccessControl::kRead, s);
-  Global(Source{{56, 78}}, "g", a, ast::StorageClass::kStorage, nullptr,
-         {
+  Global(Source{{56, 78}}, "g", a, ast::StorageClass::kStorage,
+         ast::DecorationList{
              create<ast::BindingDecoration>(0),
              create<ast::GroupDecoration>(0),
          });
@@ -163,8 +163,8 @@
   auto* ac = ty.access(ast::AccessControl::kRead, a1);
   auto* a2 = ty.alias("a2", ac);
   AST().AddConstructedType(a2);
-  Global(Source{{56, 78}}, "g", a2, ast::StorageClass::kStorage, nullptr,
-         {
+  Global(Source{{56, 78}}, "g", a2, ast::StorageClass::kStorage,
+         ast::DecorationList{
              create<ast::BindingDecoration>(0),
              create<ast::GroupDecoration>(0),
          });
@@ -177,8 +177,7 @@
 TEST_F(ResolverStorageClassValidationTest, UniformBufferBool) {
   // var<uniform> g : bool;
   Global(Source{{56, 78}}, "g", ty.bool_(), ast::StorageClass::kUniform,
-         nullptr,
-         {
+         ast::DecorationList{
              create<ast::BindingDecoration>(0),
              create<ast::GroupDecoration>(0),
          });
@@ -193,8 +192,8 @@
 TEST_F(ResolverStorageClassValidationTest, UniformBufferPointer) {
   // var<uniform> g : ptr<i32, input>;
   Global(Source{{56, 78}}, "g", ty.pointer<i32>(ast::StorageClass::kInput),
-         ast::StorageClass::kUniform, nullptr,
-         {
+         ast::StorageClass::kUniform,
+         ast::DecorationList{
              create<ast::BindingDecoration>(0),
              create<ast::GroupDecoration>(0),
          });
@@ -211,8 +210,8 @@
   auto* s = Structure("S", {Member("a", ty.f32())});
   auto* a = ty.array(s, 3);
   auto* ac = ty.access(ast::AccessControl::kRead, a);
-  Global(Source{{56, 78}}, "g", ac, ast::StorageClass::kUniform, nullptr,
-         {
+  Global(Source{{56, 78}}, "g", ac, ast::StorageClass::kUniform,
+         ast::DecorationList{
              create<ast::BindingDecoration>(0),
              create<ast::GroupDecoration>(0),
          });
@@ -229,8 +228,8 @@
   // var<uniform> g : [[access(read)]] a;
   auto* a = ty.alias("a", ty.bool_());
   AST().AddConstructedType(a);
-  Global(Source{{56, 78}}, "g", a, ast::StorageClass::kUniform, nullptr,
-         {
+  Global(Source{{56, 78}}, "g", a, ast::StorageClass::kUniform,
+         ast::DecorationList{
              create<ast::BindingDecoration>(0),
              create<ast::GroupDecoration>(0),
          });
@@ -246,8 +245,8 @@
   // struct S { x : i32 };
   // var<uniform> g : S;
   auto* s = Structure(Source{{12, 34}}, "S", {Member("x", ty.i32())});
-  Global(Source{{56, 78}}, "g", s, ast::StorageClass::kUniform, nullptr,
-         {
+  Global(Source{{56, 78}}, "g", s, ast::StorageClass::kUniform,
+         ast::DecorationList{
              create<ast::BindingDecoration>(0),
              create<ast::GroupDecoration>(0),
          });
@@ -265,8 +264,8 @@
   // var<uniform> g :  S;
   auto* s = Structure("S", {Member(Source{{12, 34}}, "x", ty.i32())},
                       {create<ast::StructBlockDecoration>()});
-  Global(Source{{56, 78}}, "g", s, ast::StorageClass::kUniform, nullptr,
-         {
+  Global(Source{{56, 78}}, "g", s, ast::StorageClass::kUniform,
+         ast::DecorationList{
              create<ast::BindingDecoration>(0),
              create<ast::GroupDecoration>(0),
          });
@@ -282,8 +281,8 @@
                       {create<ast::StructBlockDecoration>()});
   auto* a1 = ty.alias("a1", s);
   AST().AddConstructedType(a1);
-  Global(Source{{56, 78}}, "g", a1, ast::StorageClass::kUniform, nullptr,
-         {
+  Global(Source{{56, 78}}, "g", a1, ast::StorageClass::kUniform,
+         ast::DecorationList{
              create<ast::BindingDecoration>(0),
              create<ast::GroupDecoration>(0),
          });
diff --git a/src/resolver/struct_storage_class_use_test.cc b/src/resolver/struct_storage_class_use_test.cc
index 1f40bdf..46fe48d 100644
--- a/src/resolver/struct_storage_class_use_test.cc
+++ b/src/resolver/struct_storage_class_use_test.cc
@@ -173,13 +173,13 @@
   auto* s = Structure("S", {Member("a", ty.f32())},
                       {create<ast::StructBlockDecoration>()});
   auto* ac = ty.access(ast::AccessControl::kRead, s);
-  Global("x", s, ast::StorageClass::kUniform, nullptr,
-         {
+  Global("x", s, ast::StorageClass::kUniform,
+         ast::DecorationList{
              create<ast::BindingDecoration>(0),
              create<ast::GroupDecoration>(0),
          });
-  Global("y", ac, ast::StorageClass::kStorage, nullptr,
-         {
+  Global("y", ac, ast::StorageClass::kStorage,
+         ast::DecorationList{
              create<ast::BindingDecoration>(1),
              create<ast::GroupDecoration>(0),
          });
diff --git a/src/resolver/validation_test.cc b/src/resolver/validation_test.cc
index f5933fc..07356a7 100644
--- a/src/resolver/validation_test.cc
+++ b/src/resolver/validation_test.cc
@@ -345,8 +345,7 @@
 TEST_F(ResolverValidationTest, StorageClass_SamplerExplicitStorageClass) {
   auto* t = ty.sampler(ast::SamplerKind::kSampler);
   Global(Source{{12, 34}}, "var", t, ast::StorageClass::kUniformConstant,
-         nullptr,
-         {
+         ast::DecorationList{
              create<ast::BindingDecoration>(0),
              create<ast::GroupDecoration>(0),
          });
@@ -361,8 +360,7 @@
 TEST_F(ResolverValidationTest, StorageClass_TextureExplicitStorageClass) {
   auto* t = ty.sampled_texture(ast::TextureDimension::k1d, ty.f32());
   Global(Source{{12, 34}}, "var", t, ast::StorageClass::kUniformConstant,
-         nullptr,
-         {
+         ast::DecorationList{
              create<ast::BindingDecoration>(0),
              create<ast::GroupDecoration>(0),
          });
diff --git a/src/transform/msl.cc b/src/transform/msl.cc
index 1d793b5..c6a314b 100644
--- a/src/transform/msl.cc
+++ b/src/transform/msl.cc
@@ -152,7 +152,7 @@
         auto* constructor = ctx.Clone(var->Declaration()->constructor());
         auto* local_var =
             ctx.dst->Var(ctx.dst->Sym(), store_type, var->StorageClass(),
-                         constructor, {disable_validation});
+                         constructor, ast::DecorationList{disable_validation});
         ctx.InsertBefore(func_ast->body()->statements(),
                          *func_ast->body()->begin(), ctx.dst->Decl(local_var));
 
diff --git a/src/transform/spirv.cc b/src/transform/spirv.cc
index 459b1f5..e16a0f0 100644
--- a/src/transform/spirv.cc
+++ b/src/transform/spirv.cc
@@ -264,8 +264,9 @@
 
   // Create a module-scope pointsize builtin output variable.
   Symbol pointsize = ctx.dst->Symbols().New("tint_pointsize");
-  ctx.dst->Global(pointsize, ctx.dst->ty.f32(), ast::StorageClass::kOutput,
-                  nullptr, {ctx.dst->Builtin(ast::Builtin::kPointSize)});
+  ctx.dst->Global(
+      pointsize, ctx.dst->ty.f32(), ast::StorageClass::kOutput,
+      ast::DecorationList{ctx.dst->Builtin(ast::Builtin::kPointSize)});
 
   // Assign 1.0 to the global at the start of all vertex shader entry points.
   ctx.ReplaceAll([&ctx, pointsize](ast::Function* func) -> ast::Function* {
diff --git a/src/writer/hlsl/generator_impl_function_test.cc b/src/writer/hlsl/generator_impl_function_test.cc
index 187bce1..b828607 100644
--- a/src/writer/hlsl/generator_impl_function_test.cc
+++ b/src/writer/hlsl/generator_impl_function_test.cc
@@ -327,9 +327,11 @@
        Emit_Decoration_EntryPoint_With_Uniform) {
   auto* ubo_ty = Structure("UBO", {Member("coord", ty.vec4<f32>())},
                            {create<ast::StructBlockDecoration>()});
-  auto* ubo = Global(
-      "ubo", ubo_ty, ast::StorageClass::kUniform, nullptr,
-      {create<ast::BindingDecoration>(0), create<ast::GroupDecoration>(1)});
+  auto* ubo = Global("ubo", ubo_ty, ast::StorageClass::kUniform,
+                     ast::DecorationList{
+                         create<ast::BindingDecoration>(0),
+                         create<ast::GroupDecoration>(1),
+                     });
 
   Func("sub_func",
        {
@@ -380,8 +382,8 @@
   auto* s = Structure("Uniforms", {Member("coord", ty.vec4<f32>())},
                       {create<ast::StructBlockDecoration>()});
 
-  Global("uniforms", s, ast::StorageClass::kUniform, nullptr,
-         {
+  Global("uniforms", s, ast::StorageClass::kUniform,
+         ast::DecorationList{
              create<ast::BindingDecoration>(0),
              create<ast::GroupDecoration>(1),
          });
@@ -428,8 +430,8 @@
 
   auto* ac = ty.access(ast::AccessControl::kReadWrite, s);
 
-  Global("coord", ac, ast::StorageClass::kStorage, nullptr,
-         {
+  Global("coord", ac, ast::StorageClass::kStorage,
+         ast::DecorationList{
              create<ast::BindingDecoration>(0),
              create<ast::GroupDecoration>(1),
          });
@@ -474,8 +476,8 @@
 
   auto* ac = ty.access(ast::AccessControl::kRead, s);
 
-  Global("coord", ac, ast::StorageClass::kStorage, nullptr,
-         {
+  Global("coord", ac, ast::StorageClass::kStorage,
+         ast::DecorationList{
              create<ast::BindingDecoration>(0),
              create<ast::GroupDecoration>(1),
          });
@@ -520,8 +522,8 @@
 
   auto* ac = ty.access(ast::AccessControl::kWrite, s);
 
-  Global("coord", ac, ast::StorageClass::kStorage, nullptr,
-         {
+  Global("coord", ac, ast::StorageClass::kStorage,
+         ast::DecorationList{
              create<ast::BindingDecoration>(0),
              create<ast::GroupDecoration>(1),
          });
@@ -563,8 +565,8 @@
 
   auto* ac = ty.access(ast::AccessControl::kReadWrite, s);
 
-  Global("coord", ac, ast::StorageClass::kStorage, nullptr,
-         {
+  Global("coord", ac, ast::StorageClass::kStorage,
+         ast::DecorationList{
              create<ast::BindingDecoration>(0),
              create<ast::GroupDecoration>(1),
          });
@@ -599,18 +601,18 @@
 TEST_F(
     HlslGeneratorImplTest_Function,
     Emit_Decoration_Called_By_EntryPoints_WithLocationGlobals_And_Params) {  // NOLINT
-  Global("foo", ty.f32(), ast::StorageClass::kInput, nullptr,
-         {
+  Global("foo", ty.f32(), ast::StorageClass::kInput,
+         ast::DecorationList{
              Location(0),
          });
 
-  Global("bar", ty.f32(), ast::StorageClass::kOutput, nullptr,
-         {
+  Global("bar", ty.f32(), ast::StorageClass::kOutput,
+         ast::DecorationList{
              Location(1),
          });
 
-  Global("val", ty.f32(), ast::StorageClass::kOutput, nullptr,
-         {
+  Global("val", ty.f32(), ast::StorageClass::kOutput,
+         ast::DecorationList{
              Location(0),
          });
 
@@ -661,8 +663,8 @@
 
 TEST_F(HlslGeneratorImplTest_Function,
        Emit_Decoration_Called_By_EntryPoints_NoUsedGlobals) {
-  Global("depth", ty.f32(), ast::StorageClass::kOutput, nullptr,
-         {
+  Global("depth", ty.f32(), ast::StorageClass::kOutput,
+         ast::DecorationList{
              Builtin(ast::Builtin::kFragDepth),
          });
 
@@ -706,13 +708,13 @@
 TEST_F(
     HlslGeneratorImplTest_Function,
     Emit_Decoration_Called_By_EntryPoints_WithBuiltinGlobals_And_Params) {  // NOLINT
-  Global("coord", ty.vec4<f32>(), ast::StorageClass::kInput, nullptr,
-         {
+  Global("coord", ty.vec4<f32>(), ast::StorageClass::kInput,
+         ast::DecorationList{
              Builtin(ast::Builtin::kPosition),
          });
 
-  Global("depth", ty.f32(), ast::StorageClass::kOutput, nullptr,
-         {
+  Global("depth", ty.f32(), ast::StorageClass::kOutput,
+         ast::DecorationList{
              Builtin(ast::Builtin::kFragDepth),
          });
 
@@ -762,8 +764,8 @@
        Emit_Decoration_Called_By_EntryPoint_With_Uniform) {
   auto* s = Structure("S", {Member("x", ty.f32())},
                       {create<ast::StructBlockDecoration>()});
-  Global("coord", s, ast::StorageClass::kUniform, nullptr,
-         {
+  Global("coord", s, ast::StorageClass::kUniform,
+         ast::DecorationList{
              create<ast::BindingDecoration>(0),
              create<ast::GroupDecoration>(1),
          });
@@ -813,8 +815,8 @@
   auto* s = Structure("S", {Member("x", ty.f32())},
                       {create<ast::StructBlockDecoration>()});
   auto* ac = ty.access(ast::AccessControl::kReadWrite, s);
-  Global("coord", ac, ast::StorageClass::kStorage, nullptr,
-         {
+  Global("coord", ac, ast::StorageClass::kStorage,
+         ast::DecorationList{
              create<ast::BindingDecoration>(0),
              create<ast::GroupDecoration>(1),
          });
@@ -859,8 +861,8 @@
 
 TEST_F(HlslGeneratorImplTest_Function,
        Emit_Decoration_EntryPoints_WithGlobal_Nested_Return) {
-  Global("bar", ty.f32(), ast::StorageClass::kOutput, nullptr,
-         {
+  Global("bar", ty.f32(), ast::StorageClass::kOutput,
+         ast::DecorationList{
              Location(1),
          });
 
@@ -1064,8 +1066,8 @@
 
   auto* ac = ty.access(ast::AccessControl::kReadWrite, s);
 
-  Global("data", ac, ast::StorageClass::kStorage, nullptr,
-         {
+  Global("data", ac, ast::StorageClass::kStorage,
+         ast::DecorationList{
              create<ast::BindingDecoration>(0),
              create<ast::GroupDecoration>(0),
          });
diff --git a/src/writer/hlsl/generator_impl_sanitizer_test.cc b/src/writer/hlsl/generator_impl_sanitizer_test.cc
index 8691319..7e16d5b 100644
--- a/src/writer/hlsl/generator_impl_sanitizer_test.cc
+++ b/src/writer/hlsl/generator_impl_sanitizer_test.cc
@@ -35,8 +35,8 @@
                           });
   auto* ac_ty = ty.access(ast::AccessControl::kRead, sb_ty);
 
-  Global("sb", ac_ty, ast::StorageClass::kStorage, nullptr,
-         {
+  Global("sb", ac_ty, ast::StorageClass::kStorage,
+         ast::DecorationList{
              create<ast::BindingDecoration>(0),
              create<ast::GroupDecoration>(1),
          });
diff --git a/src/writer/hlsl/generator_impl_type_test.cc b/src/writer/hlsl/generator_impl_type_test.cc
index 200cd76..090e077 100644
--- a/src/writer/hlsl/generator_impl_type_test.cc
+++ b/src/writer/hlsl/generator_impl_type_test.cc
@@ -190,8 +190,8 @@
                       },
                       {create<ast::StructBlockDecoration>()});
   Global("g", ty.access(ast::AccessControl::kReadWrite, s),
-         ast::StorageClass::kStorage, nullptr,
-         {
+         ast::StorageClass::kStorage,
+         ast::DecorationList{
              create<ast::BindingDecoration>(0),
              create<ast::GroupDecoration>(0),
          });
diff --git a/src/writer/msl/generator_impl_function_test.cc b/src/writer/msl/generator_impl_function_test.cc
index d3641f1..7c19271 100644
--- a/src/writer/msl/generator_impl_function_test.cc
+++ b/src/writer/msl/generator_impl_function_test.cc
@@ -308,8 +308,11 @@
 
   auto* ac = ty.access(ast::AccessControl::kReadWrite, s);
 
-  Global("coord", ac, ast::StorageClass::kStorage, nullptr,
-         {create<ast::BindingDecoration>(0), create<ast::GroupDecoration>(1)});
+  Global("coord", ac, ast::StorageClass::kStorage,
+         ast::DecorationList{
+             create<ast::BindingDecoration>(0),
+             create<ast::GroupDecoration>(1),
+         });
 
   auto* var = Var("v", ty.f32(), ast::StorageClass::kNone,
                   MemberAccessor("coord", "b"));
@@ -353,8 +356,11 @@
 
   auto* ac = ty.access(ast::AccessControl::kRead, s);
 
-  Global("coord", ac, ast::StorageClass::kStorage, nullptr,
-         {create<ast::BindingDecoration>(0), create<ast::GroupDecoration>(1)});
+  Global("coord", ac, ast::StorageClass::kStorage,
+         ast::DecorationList{
+             create<ast::BindingDecoration>(0),
+             create<ast::GroupDecoration>(1),
+         });
 
   auto* var = Var("v", ty.f32(), ast::StorageClass::kNone,
                   MemberAccessor("coord", "b"));
@@ -391,11 +397,16 @@
 TEST_F(
     MslGeneratorImplTest,
     Emit_Decoration_Called_By_EntryPoints_WithLocationGlobals_And_Params) {  // NOLINT
-  Global("foo", ty.f32(), ast::StorageClass::kInput, nullptr, {Location(0)});
+  Global("foo", ty.f32(), ast::StorageClass::kInput,
+         ast::DecorationList{Location(0)});
 
-  Global("bar", ty.f32(), ast::StorageClass::kOutput, nullptr, {Location(1)});
+  Global("bar", ty.f32(), ast::StorageClass::kOutput,
+         ast::DecorationList{
+             Location(1),
+         });
 
-  Global("val", ty.f32(), ast::StorageClass::kOutput, nullptr, {Location(0)});
+  Global("val", ty.f32(), ast::StorageClass::kOutput,
+         ast::DecorationList{Location(0)});
 
   ast::VariableList params;
   params.push_back(Param("param", ty.f32()));
@@ -448,8 +459,8 @@
 // TODO(crbug.com/tint/697): Remove this test
 TEST_F(MslGeneratorImplTest,
        Emit_Decoration_Called_By_EntryPoints_NoUsedGlobals) {
-  Global("depth", ty.f32(), ast::StorageClass::kOutput, nullptr,
-         {Builtin(ast::Builtin::kFragDepth)});
+  Global("depth", ty.f32(), ast::StorageClass::kOutput,
+         ast::DecorationList{Builtin(ast::Builtin::kFragDepth)});
 
   ast::VariableList params;
   params.push_back(Param("param", ty.f32()));
@@ -497,11 +508,11 @@
 TEST_F(
     MslGeneratorImplTest,
     Emit_Decoration_Called_By_EntryPoints_WithBuiltinGlobals_And_Params) {  // NOLINT
-  Global("coord", ty.vec4<f32>(), ast::StorageClass::kInput, nullptr,
-         {Builtin(ast::Builtin::kPosition)});
+  Global("coord", ty.vec4<f32>(), ast::StorageClass::kInput,
+         ast::DecorationList{Builtin(ast::Builtin::kPosition)});
 
-  Global("depth", ty.f32(), ast::StorageClass::kOutput, nullptr,
-         {Builtin(ast::Builtin::kFragDepth)});
+  Global("depth", ty.f32(), ast::StorageClass::kOutput,
+         ast::DecorationList{Builtin(ast::Builtin::kFragDepth)});
 
   ast::VariableList params;
   params.push_back(Param("param", ty.f32()));
@@ -551,9 +562,11 @@
        Emit_Decoration_Called_By_EntryPoint_With_Uniform) {
   auto* ubo_ty = Structure("UBO", {Member("coord", ty.vec4<f32>())},
                            {create<ast::StructBlockDecoration>()});
-  auto* ubo = Global(
-      "ubo", ubo_ty, ast::StorageClass::kUniform, nullptr,
-      {create<ast::BindingDecoration>(0), create<ast::GroupDecoration>(1)});
+  auto* ubo = Global("ubo", ubo_ty, ast::StorageClass::kUniform,
+                     ast::DecorationList{
+                         create<ast::BindingDecoration>(0),
+                         create<ast::GroupDecoration>(1),
+                     });
 
   Func("sub_func",
        {
@@ -609,8 +622,11 @@
 
   auto* ac = ty.access(ast::AccessControl::kReadWrite, s);
 
-  Global("coord", ac, ast::StorageClass::kStorage, nullptr,
-         {create<ast::BindingDecoration>(0), create<ast::GroupDecoration>(1)});
+  Global("coord", ac, ast::StorageClass::kStorage,
+         ast::DecorationList{
+             create<ast::BindingDecoration>(0),
+             create<ast::GroupDecoration>(1),
+         });
 
   ast::VariableList params;
   params.push_back(Param("param", ty.f32()));
@@ -665,8 +681,11 @@
 
   auto* ac = ty.access(ast::AccessControl::kRead, s);
 
-  Global("coord", ac, ast::StorageClass::kStorage, nullptr,
-         {create<ast::BindingDecoration>(0), create<ast::GroupDecoration>(1)});
+  Global("coord", ac, ast::StorageClass::kStorage,
+         ast::DecorationList{
+             create<ast::BindingDecoration>(0),
+             create<ast::GroupDecoration>(1),
+         });
 
   ast::VariableList params;
   params.push_back(Param("param", ty.f32()));
@@ -713,7 +732,10 @@
 // TODO(crbug.com/tint/697): Remove this test
 TEST_F(MslGeneratorImplTest,
        Emit_Decoration_EntryPoints_WithGlobal_Nested_Return) {
-  Global("bar", ty.f32(), ast::StorageClass::kOutput, nullptr, {Location(1)});
+  Global("bar", ty.f32(), ast::StorageClass::kOutput,
+         ast::DecorationList{
+             Location(1),
+         });
 
   auto* list = Block(Return());
 
@@ -804,8 +826,11 @@
 
   auto* ac = ty.access(ast::AccessControl::kReadWrite, s);
 
-  Global("data", ac, ast::StorageClass::kStorage, nullptr,
-         {create<ast::BindingDecoration>(0), create<ast::GroupDecoration>(0)});
+  Global("data", ac, ast::StorageClass::kStorage,
+         ast::DecorationList{
+             create<ast::BindingDecoration>(0),
+             create<ast::GroupDecoration>(0),
+         });
 
   {
     auto* var = Var("v", ty.f32(), ast::StorageClass::kNone,
diff --git a/src/writer/msl/generator_impl_type_test.cc b/src/writer/msl/generator_impl_type_test.cc
index 7eaf660..235fc26 100644
--- a/src/writer/msl/generator_impl_type_test.cc
+++ b/src/writer/msl/generator_impl_type_test.cc
@@ -233,8 +233,8 @@
                 {create<ast::StructBlockDecoration>()});
 
   Global("G", ty.access(ast::AccessControl::kRead, s),
-         ast::StorageClass::kStorage, nullptr,
-         {
+         ast::StorageClass::kStorage,
+         ast::DecorationList{
              create<ast::BindingDecoration>(0),
              create<ast::GroupDecoration>(0),
          });
@@ -343,8 +343,8 @@
                       {create<ast::StructBlockDecoration>()});
 
   Global("G", ty.access(ast::AccessControl::kRead, s),
-         ast::StorageClass::kStorage, nullptr,
-         {
+         ast::StorageClass::kStorage,
+         ast::DecorationList{
              create<ast::BindingDecoration>(0),
              create<ast::GroupDecoration>(0),
          });
@@ -438,8 +438,8 @@
                 ast::DecorationList{create<ast::StructBlockDecoration>()});
 
   Global("G", ty.access(ast::AccessControl::kRead, s),
-         ast::StorageClass::kStorage, nullptr,
-         {
+         ast::StorageClass::kStorage,
+         ast::DecorationList{
              create<ast::BindingDecoration>(0),
              create<ast::GroupDecoration>(0),
          });
@@ -552,8 +552,8 @@
       {create<ast::StructBlockDecoration>()});
 
   Global("G", ty.access(ast::AccessControl::kRead, s),
-         ast::StorageClass::kStorage, nullptr,
-         {
+         ast::StorageClass::kStorage,
+         ast::DecorationList{
              create<ast::BindingDecoration>(0),
              create<ast::GroupDecoration>(0),
          });
@@ -618,8 +618,8 @@
                       {create<ast::StructBlockDecoration>()});
 
   Global("G", ty.access(ast::AccessControl::kRead, s),
-         ast::StorageClass::kStorage, nullptr,
-         {
+         ast::StorageClass::kStorage,
+         ast::DecorationList{
              create<ast::BindingDecoration>(0),
              create<ast::GroupDecoration>(0),
          });
@@ -774,8 +774,8 @@
   auto* s = ty.storage_texture(params.dim, ast::ImageFormat::kR32Float);
   auto* ac = ty.access(
       params.ro ? ast::AccessControl::kRead : ast::AccessControl::kWrite, s);
-  Global("test_var", ac, ast::StorageClass::kNone, nullptr,
-         {
+  Global("test_var", ac,
+         ast::DecorationList{
              create<ast::BindingDecoration>(0),
              create<ast::GroupDecoration>(0),
          });
diff --git a/src/writer/spirv/builder_global_variable_test.cc b/src/writer/spirv/builder_global_variable_test.cc
index 0ec6189..622e7df 100644
--- a/src/writer/spirv/builder_global_variable_test.cc
+++ b/src/writer/spirv/builder_global_variable_test.cc
@@ -404,8 +404,8 @@
                       {create<ast::StructBlockDecoration>()});
   auto* ac = ty.access(ast::AccessControl::kRead, A);
 
-  auto* var = Global("b", ac, ast::StorageClass::kStorage, nullptr,
-                     {
+  auto* var = Global("b", ac, ast::StorageClass::kStorage,
+                     ast::DecorationList{
                          create<ast::BindingDecoration>(0),
                          create<ast::GroupDecoration>(0),
                      });
@@ -445,8 +445,8 @@
   auto* B = ty.alias("B", A);
   AST().AddConstructedType(B);
   auto* ac = ty.access(ast::AccessControl::kRead, B);
-  auto* var = Global("b", ac, ast::StorageClass::kStorage, nullptr,
-                     {
+  auto* var = Global("b", ac, ast::StorageClass::kStorage,
+                     ast::DecorationList{
                          create<ast::BindingDecoration>(0),
                          create<ast::GroupDecoration>(0),
                      });
@@ -484,8 +484,8 @@
   auto* ac = ty.access(ast::AccessControl::kRead, A);
   auto* B = ty.alias("B", ac);
   AST().AddConstructedType(B);
-  auto* var = Global("b", B, ast::StorageClass::kStorage, nullptr,
-                     {
+  auto* var = Global("b", B, ast::StorageClass::kStorage,
+                     ast::DecorationList{
                          create<ast::BindingDecoration>(0),
                          create<ast::GroupDecoration>(0),
                      });
@@ -523,13 +523,13 @@
   auto* read = ty.access(ast::AccessControl::kRead, A);
   auto* rw = ty.access(ast::AccessControl::kReadWrite, A);
 
-  auto* var_b = Global("b", read, ast::StorageClass::kStorage, nullptr,
-                       {
+  auto* var_b = Global("b", read, ast::StorageClass::kStorage,
+                       ast::DecorationList{
                            create<ast::GroupDecoration>(0),
                            create<ast::BindingDecoration>(0),
                        });
-  auto* var_c = Global("c", rw, ast::StorageClass::kStorage, nullptr,
-                       {
+  auto* var_c = Global("c", rw, ast::StorageClass::kStorage,
+                       ast::DecorationList{
                            create<ast::GroupDecoration>(1),
                            create<ast::BindingDecoration>(0),
                        });
@@ -569,8 +569,8 @@
 
   auto* ac = ty.access(ast::AccessControl::kRead, type);
 
-  auto* var_a = Global("a", ac, ast::StorageClass::kNone, nullptr,
-                       {
+  auto* var_a = Global("a", ac, ast::StorageClass::kNone,
+                       ast::DecorationList{
                            create<ast::BindingDecoration>(0),
                            create<ast::GroupDecoration>(0),
                        });
@@ -598,8 +598,8 @@
 
   auto* ac = ty.access(ast::AccessControl::kWrite, type);
 
-  auto* var_a = Global("a", ac, ast::StorageClass::kNone, nullptr,
-                       {
+  auto* var_a = Global("a", ac, ast::StorageClass::kNone,
+                       ast::DecorationList{
                            create<ast::BindingDecoration>(0),
                            create<ast::GroupDecoration>(0),
                        });
@@ -628,8 +628,8 @@
   auto* type_a = ty.access(ast::AccessControl::kRead,
                            ty.storage_texture(ast::TextureDimension::k2d,
                                               ast::ImageFormat::kR32Uint));
-  auto* var_a = Global("a", type_a, ast::StorageClass::kNone, nullptr,
-                       {
+  auto* var_a = Global("a", type_a, ast::StorageClass::kNone,
+                       ast::DecorationList{
                            create<ast::BindingDecoration>(0),
                            create<ast::GroupDecoration>(0),
                        });
@@ -637,8 +637,8 @@
   auto* type_b = ty.access(ast::AccessControl::kWrite,
                            ty.storage_texture(ast::TextureDimension::k2d,
                                               ast::ImageFormat::kR32Uint));
-  auto* var_b = Global("b", type_b, ast::StorageClass::kNone, nullptr,
-                       {
+  auto* var_b = Global("b", type_b, ast::StorageClass::kNone,
+                       ast::DecorationList{
                            create<ast::BindingDecoration>(1),
                            create<ast::GroupDecoration>(0),
                        });
diff --git a/src/writer/spirv/builder_intrinsic_test.cc b/src/writer/spirv/builder_intrinsic_test.cc
index 4e4238a..6a09d5c 100644
--- a/src/writer/spirv/builder_intrinsic_test.cc
+++ b/src/writer/spirv/builder_intrinsic_test.cc
@@ -521,14 +521,14 @@
   auto* s = ty.sampler(ast::SamplerKind::kComparisonSampler);
   auto* t = ty.depth_texture(ast::TextureDimension::k2d);
 
-  auto* tex = Global("texture", t, ast::StorageClass::kNone, nullptr,
-                     {
+  auto* tex = Global("texture", t,
+                     ast::DecorationList{
                          create<ast::BindingDecoration>(0),
                          create<ast::GroupDecoration>(0),
                      });
 
-  auto* sampler = Global("sampler", s, ast::StorageClass::kNone, nullptr,
-                         {
+  auto* sampler = Global("sampler", s,
+                         ast::DecorationList{
                              create<ast::BindingDecoration>(1),
                              create<ast::GroupDecoration>(0),
                          });
diff --git a/src/writer/spirv/builder_type_test.cc b/src/writer/spirv/builder_type_test.cc
index d5feda5..83168ca 100644
--- a/src/writer/spirv/builder_type_test.cc
+++ b/src/writer/spirv/builder_type_test.cc
@@ -31,8 +31,8 @@
   auto* str = Structure("S", {Member("x", ary)},
                         {create<ast::StructBlockDecoration>()});
   auto* ac = ty.access(ast::AccessControl::kRead, str);
-  Global("a", ac, ast::StorageClass::kStorage, nullptr,
-         {
+  Global("a", ac, ast::StorageClass::kStorage,
+         ast::DecorationList{
              create<ast::BindingDecoration>(0),
              create<ast::GroupDecoration>(0),
          });
@@ -53,8 +53,8 @@
   auto* str = Structure("S", {Member("x", ary)},
                         {create<ast::StructBlockDecoration>()});
   auto* ac = ty.access(ast::AccessControl::kRead, str);
-  Global("a", ac, ast::StorageClass::kStorage, nullptr,
-         {
+  Global("a", ac, ast::StorageClass::kStorage,
+         ast::DecorationList{
              create<ast::BindingDecoration>(0),
              create<ast::GroupDecoration>(0),
          });
@@ -834,8 +834,8 @@
                                ast::ImageFormat::kR32Float);
   auto* ac = ty.access(ast::AccessControl::kRead, s);
 
-  Global("test_var", ac, ast::StorageClass::kNone, nullptr,
-         {
+  Global("test_var", ac,
+         ast::DecorationList{
              create<ast::BindingDecoration>(0),
              create<ast::GroupDecoration>(0),
          });
@@ -854,8 +854,8 @@
                                ast::ImageFormat::kR32Float);
   auto* ac = ty.access(ast::AccessControl::kRead, s);
 
-  Global("test_var", ac, ast::StorageClass::kNone, nullptr,
-         {
+  Global("test_var", ac,
+         ast::DecorationList{
              create<ast::BindingDecoration>(0),
              create<ast::GroupDecoration>(0),
          });
@@ -874,8 +874,8 @@
                                ast::ImageFormat::kR32Float);
   auto* ac = ty.access(ast::AccessControl::kRead, s);
 
-  Global("test_var", ac, ast::StorageClass::kNone, nullptr,
-         {
+  Global("test_var", ac,
+         ast::DecorationList{
              create<ast::BindingDecoration>(0),
              create<ast::GroupDecoration>(0),
          });
@@ -894,8 +894,8 @@
                                ast::ImageFormat::kR32Float);
   auto* ac = ty.access(ast::AccessControl::kRead, s);
 
-  Global("test_var", ac, ast::StorageClass::kNone, nullptr,
-         {
+  Global("test_var", ac,
+         ast::DecorationList{
              create<ast::BindingDecoration>(0),
              create<ast::GroupDecoration>(0),
          });
@@ -915,8 +915,8 @@
                                ast::ImageFormat::kR32Float);
   auto* ac = ty.access(ast::AccessControl::kRead, s);
 
-  Global("test_var", ac, ast::StorageClass::kNone, nullptr,
-         {
+  Global("test_var", ac,
+         ast::DecorationList{
              create<ast::BindingDecoration>(0),
              create<ast::GroupDecoration>(0),
          });
@@ -936,8 +936,8 @@
                                ast::ImageFormat::kR32Sint);
   auto* ac = ty.access(ast::AccessControl::kRead, s);
 
-  Global("test_var", ac, ast::StorageClass::kNone, nullptr,
-         {
+  Global("test_var", ac,
+         ast::DecorationList{
              create<ast::BindingDecoration>(0),
              create<ast::GroupDecoration>(0),
          });
@@ -957,8 +957,8 @@
                                ast::ImageFormat::kR32Uint);
   auto* ac = ty.access(ast::AccessControl::kRead, s);
 
-  Global("test_var", ac, ast::StorageClass::kNone, nullptr,
-         {
+  Global("test_var", ac,
+         ast::DecorationList{
              create<ast::BindingDecoration>(0),
              create<ast::GroupDecoration>(0),
          });
diff --git a/src/writer/wgsl/generator_impl_global_decl_test.cc b/src/writer/wgsl/generator_impl_global_decl_test.cc
index 83a6a83..45bb89f 100644
--- a/src/writer/wgsl/generator_impl_global_decl_test.cc
+++ b/src/writer/wgsl/generator_impl_global_decl_test.cc
@@ -100,9 +100,11 @@
 }
 
 TEST_F(WgslGeneratorImplTest, Emit_Global_Sampler) {
-  Global("s", ty.sampler(ast::SamplerKind::kSampler), ast::StorageClass::kNone,
-         nullptr,
-         {create<ast::GroupDecoration>(0), create<ast::BindingDecoration>(0)});
+  Global("s", ty.sampler(ast::SamplerKind::kSampler),
+         ast::DecorationList{
+             create<ast::GroupDecoration>(0),
+             create<ast::BindingDecoration>(0),
+         });
 
   GeneratorImpl& gen = Build();
 
@@ -115,8 +117,10 @@
 TEST_F(WgslGeneratorImplTest, Emit_Global_Texture) {
   auto* st = ty.sampled_texture(ast::TextureDimension::k1d, ty.f32());
   Global("t", ty.access(ast::AccessControl::kRead, st),
-         ast::StorageClass::kNone, nullptr,
-         {create<ast::GroupDecoration>(0), create<ast::BindingDecoration>(0)});
+         ast::DecorationList{
+             create<ast::GroupDecoration>(0),
+             create<ast::BindingDecoration>(0),
+         });
 
   GeneratorImpl& gen = Build();