ast: Support override decorations without IDs

Bug: tint:755
Change-Id: I33f6535b4f3f03826d6f4dd531dc6967f476402b
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/50840
Reviewed-by: Ben Clayton <bclayton@google.com>
Commit-Queue: James Price <jrprice@google.com>
diff --git a/src/ast/override_decoration.cc b/src/ast/override_decoration.cc
index c50a993..bf32a48 100644
--- a/src/ast/override_decoration.cc
+++ b/src/ast/override_decoration.cc
@@ -22,9 +22,13 @@
 namespace ast {
 
 OverrideDecoration::OverrideDecoration(ProgramID program_id,
+                                       const Source& source)
+    : Base(program_id, source), has_value_(false), value_(0) {}
+
+OverrideDecoration::OverrideDecoration(ProgramID program_id,
                                        const Source& source,
                                        uint32_t val)
-    : Base(program_id, source), value_(val) {}
+    : Base(program_id, source), has_value_(true), value_(val) {}
 
 OverrideDecoration::~OverrideDecoration() = default;
 
@@ -32,13 +36,21 @@
                                 std::ostream& out,
                                 size_t indent) const {
   make_indent(out, indent);
-  out << "OverrideDecoration{" << value_ << "}" << std::endl;
+  out << "OverrideDecoration";
+  if (has_value_) {
+    out << "{" << value_ << "}";
+  }
+  out << std::endl;
 }
 
 OverrideDecoration* OverrideDecoration::Clone(CloneContext* ctx) const {
   // Clone arguments outside of create() call to have deterministic ordering
   auto src = ctx->Clone(source());
-  return ctx->dst->create<OverrideDecoration>(src, value_);
+  if (has_value_) {
+    return ctx->dst->create<OverrideDecoration>(src, value_);
+  } else {
+    return ctx->dst->create<OverrideDecoration>(src);
+  }
 }
 
 }  // namespace ast
diff --git a/src/ast/override_decoration.h b/src/ast/override_decoration.h
index b2f8b3b..f5c6090 100644
--- a/src/ast/override_decoration.h
+++ b/src/ast/override_decoration.h
@@ -23,13 +23,20 @@
 /// An override decoration
 class OverrideDecoration : public Castable<OverrideDecoration, Decoration> {
  public:
-  /// constructor
+  /// Create an override decoration with no specified id.
+  /// @param program_id the identifier of the program that owns this node
+  /// @param source the source of this decoration
+  OverrideDecoration(ProgramID program_id, const Source& source);
+  /// Create an override decoration with a specific id value.
   /// @param program_id the identifier of the program that owns this node
   /// @param source the source of this decoration
   /// @param val the override value
   OverrideDecoration(ProgramID program_id, const Source& source, uint32_t val);
   ~OverrideDecoration() override;
 
+  /// @returns true if an override id was specified
+  uint32_t HasValue() const { return has_value_; }
+
   /// @returns the override id value
   uint32_t value() const { return value_; }
 
@@ -48,6 +55,7 @@
   OverrideDecoration* Clone(CloneContext* ctx) const override;
 
  private:
+  bool has_value_;
   uint32_t const value_;
 };
 
diff --git a/src/ast/override_decoration_test.cc b/src/ast/override_decoration_test.cc
index 078563c..fe1d151 100644
--- a/src/ast/override_decoration_test.cc
+++ b/src/ast/override_decoration_test.cc
@@ -22,11 +22,17 @@
 
 using OverrideDecorationTest = TestHelper;
 
-TEST_F(OverrideDecorationTest, Creation) {
+TEST_F(OverrideDecorationTest, Creation_WithValue) {
   auto* d = create<OverrideDecoration>(12);
+  EXPECT_TRUE(d->HasValue());
   EXPECT_EQ(12u, d->value());
 }
 
+TEST_F(OverrideDecorationTest, Creation_WithoutValue) {
+  auto* d = create<OverrideDecoration>();
+  EXPECT_FALSE(d->HasValue());
+}
+
 TEST_F(OverrideDecorationTest, ToStr) {
   auto* d = create<OverrideDecoration>(1200);
   EXPECT_EQ(str(d), R"(OverrideDecoration{1200}