[tint][wgsl] Add ColorAttribute
Not yet parsed, not yet resolved.
Bug: tint:2085
Change-Id: If94b6c5929265117dc87f81a34a0280aa5b14def
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/159602
Reviewed-by: James Price <jrprice@google.com>
Commit-Queue: Ben Clayton <bclayton@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
diff --git a/src/tint/lang/core/attribute.cc b/src/tint/lang/core/attribute.cc
index 7b18915..2568294 100644
--- a/src/tint/lang/core/attribute.cc
+++ b/src/tint/lang/core/attribute.cc
@@ -51,6 +51,9 @@
if (str == "builtin") {
return Attribute::kBuiltin;
}
+ if (str == "color") {
+ return Attribute::kColor;
+ }
if (str == "compute") {
return Attribute::kCompute;
}
@@ -103,6 +106,8 @@
return "binding";
case Attribute::kBuiltin:
return "builtin";
+ case Attribute::kColor:
+ return "color";
case Attribute::kCompute:
return "compute";
case Attribute::kDiagnostic:
diff --git a/src/tint/lang/core/attribute.h b/src/tint/lang/core/attribute.h
index 3e7b087..46d7619 100644
--- a/src/tint/lang/core/attribute.h
+++ b/src/tint/lang/core/attribute.h
@@ -52,6 +52,7 @@
kAlign,
kBinding,
kBuiltin,
+ kColor,
kCompute,
kDiagnostic,
kFragment,
@@ -85,9 +86,9 @@
Attribute ParseAttribute(std::string_view str);
constexpr std::string_view kAttributeStrings[] = {
- "align", "binding", "builtin", "compute", "diagnostic", "fragment",
- "group", "id", "index", "interpolate", "invariant", "location",
- "must_use", "size", "vertex", "workgroup_size",
+ "align", "binding", "builtin", "color", "compute", "diagnostic",
+ "fragment", "group", "id", "index", "interpolate", "invariant",
+ "location", "must_use", "size", "vertex", "workgroup_size",
};
} // namespace tint::core
diff --git a/src/tint/lang/core/attribute_bench.cc b/src/tint/lang/core/attribute_bench.cc
index 1621a94..16a660c 100644
--- a/src/tint/lang/core/attribute_bench.cc
+++ b/src/tint/lang/core/attribute_bench.cc
@@ -66,97 +66,104 @@
"Euiltin",
"bPTTltin",
"builtdxx",
- "c44mpute",
- "coSSpuVVe",
- "RomR22e",
+ "c44lor",
+ "coVVSSr",
+ "22RRr",
+ "color",
+ "cFor",
+ "colr",
+ "ROOHVr",
+ "copuye",
+ "llnorrp77te",
+ "comp4t00",
"compute",
- "cFpu9e",
- "comute",
- "VOORRHte",
- "dyagnstic",
- "d77agnnnsllrrc",
- "dia400ostic",
+ "opooe",
+ "zzpute",
+ "ciimppu1",
+ "XXiagnostic",
+ "IIia99nonnt55c",
+ "dYagSSrrstHHac",
"diagnostic",
- "danstooc",
- "dignszzic",
- "d11ansppiic",
- "XXragment",
- "fIIa9955nnnt",
- "aarHHgmenYSS",
+ "dakkoHtc",
+ "jiagnsgRR",
+ "diagbost",
+ "fragjent",
+ "fragmnt",
+ "frqent",
"fragment",
- "fkkaet",
- "gjamRRn",
- "fabmnt",
- "gjoup",
- "goup",
- "goq",
+ "fragenNN",
+ "ravvent",
+ "frgmQQnt",
+ "grof",
+ "grojp",
+ "NNrw2u",
"group",
- "Nroup",
- "govv",
- "gruQQ",
- "r",
- "jd",
- "NNw",
+ "grup",
+ "grroup",
+ "Group",
+ "iFF",
+ "NN",
+ "iAA",
"id",
- "i",
- "rrd",
- "iG",
- "inFFex",
- "iE",
- "inrrx",
+ "d",
+ "L",
+ "yy",
+ "nek",
+ "indx",
+ "Jndx",
"index",
- "inx",
- "inJJD",
- "ie",
- "inerpklae",
- "intrpolate",
- "inJerpolae",
+ "incex",
+ "iOdex",
+ "__nttKKvv",
+ "int8rpoxx5e",
+ "inteqq__lte",
+ "interpqlate",
"interpolate",
- "interpocate",
- "interpolaOe",
- "__nttevvpoKKate",
- "xnvari5n8",
- "inFq__ant",
- "iqqariant",
+ "33ntOpolat66",
+ "intoott6QQlate",
+ "66terpolate",
+ "zzxvO6rint",
+ "invayyiant",
+ "HHnariZt",
"invariant",
- "invar6a33O",
- "i96arQttanoo",
- "inari66nt",
- "lOxati6zz",
- "locyytion",
- "lHHtion",
+ "iWW44rianq",
+ "iOOvaiant",
+ "ivariYnt",
+ "ltion",
+ "loaFion",
+ "wocatio",
"location",
- "qWW4caton",
- "locOOton",
- "ocatiYn",
- "m_use",
- "mutFuse",
- "wust_us",
+ "Kcatoff",
+ "qocKKtion",
+ "lFcmmt3on",
+ "mustuse",
+ "must_se",
+ "ubbt_ube",
"must_use",
- "Kst_sff",
- "qusKK_use",
- "mFsmm_3se",
- "ize",
- "sze",
- "sbbb",
+ "mstiius",
+ "muqt_uOe",
+ "muTTt_usvv",
+ "FFize",
+ "QP00",
+ "siPe",
"size",
- "iie",
- "siqe",
- "svvTTe",
- "vertFFx",
- "vrQ00P",
- "vePtex",
+ "sis77",
+ "CiRbbe",
+ "sizXX",
+ "CCrtOOOO",
+ "vrsuL",
+ "verteX",
"vertex",
- "vsste77",
- "veCtRRbb",
- "verteXX",
- "workgqou_siCCOOO",
- "worsgroupsuzL",
- "wXrkgroup_size",
+ "verte",
+ "qqrx",
+ "verte22",
+ "workgou0yzzizXX",
+ "workgrop_VPize",
+ "wokgroupnnsCze",
"workgroup_size",
- "workgroup_sze",
- "wqqrOgoupize",
- "workg22oup_size",
+ "workgrouq_sizHA",
+ "workgrup_size",
+ "forroupKKsize",
};
for (auto _ : state) {
for (auto* str : kStrings) {
diff --git a/src/tint/lang/core/attribute_test.cc b/src/tint/lang/core/attribute_test.cc
index 58e03ab..ac6b338 100644
--- a/src/tint/lang/core/attribute_test.cc
+++ b/src/tint/lang/core/attribute_test.cc
@@ -57,14 +57,23 @@
}
static constexpr Case kValidCases[] = {
- {"align", Attribute::kAlign}, {"binding", Attribute::kBinding},
- {"builtin", Attribute::kBuiltin}, {"compute", Attribute::kCompute},
- {"diagnostic", Attribute::kDiagnostic}, {"fragment", Attribute::kFragment},
- {"group", Attribute::kGroup}, {"id", Attribute::kId},
- {"index", Attribute::kIndex}, {"interpolate", Attribute::kInterpolate},
- {"invariant", Attribute::kInvariant}, {"location", Attribute::kLocation},
- {"must_use", Attribute::kMustUse}, {"size", Attribute::kSize},
- {"vertex", Attribute::kVertex}, {"workgroup_size", Attribute::kWorkgroupSize},
+ {"align", Attribute::kAlign},
+ {"binding", Attribute::kBinding},
+ {"builtin", Attribute::kBuiltin},
+ {"color", Attribute::kColor},
+ {"compute", Attribute::kCompute},
+ {"diagnostic", Attribute::kDiagnostic},
+ {"fragment", Attribute::kFragment},
+ {"group", Attribute::kGroup},
+ {"id", Attribute::kId},
+ {"index", Attribute::kIndex},
+ {"interpolate", Attribute::kInterpolate},
+ {"invariant", Attribute::kInvariant},
+ {"location", Attribute::kLocation},
+ {"must_use", Attribute::kMustUse},
+ {"size", Attribute::kSize},
+ {"vertex", Attribute::kVertex},
+ {"workgroup_size", Attribute::kWorkgroupSize},
};
static constexpr Case kInvalidCases[] = {
@@ -77,45 +86,48 @@
{"ppqqiliHH", Attribute::kUndefined},
{"bucv", Attribute::kUndefined},
{"biltGn", Attribute::kUndefined},
- {"compiive", Attribute::kUndefined},
- {"8WWmpute", Attribute::kUndefined},
- {"cxxpute", Attribute::kUndefined},
- {"dXagnosigg", Attribute::kUndefined},
- {"dagnXuVc", Attribute::kUndefined},
- {"diagnosti3", Attribute::kUndefined},
- {"fraEment", Attribute::kUndefined},
- {"PPagTTent", Attribute::kUndefined},
- {"xxragddnt", Attribute::kUndefined},
- {"g44oup", Attribute::kUndefined},
- {"grVVSSp", Attribute::kUndefined},
- {"22RRp", Attribute::kUndefined},
- {"d", Attribute::kUndefined},
- {"i", Attribute::kUndefined},
- {"OVd", Attribute::kUndefined},
- {"ndyx", Attribute::kUndefined},
- {"n77rrldGx", Attribute::kUndefined},
- {"inde40", Attribute::kUndefined},
- {"itooolate", Attribute::kUndefined},
- {"intezplate", Attribute::kUndefined},
- {"ppnerii1olat", Attribute::kUndefined},
- {"invarianXX", Attribute::kUndefined},
- {"inv55ria99nII", Attribute::kUndefined},
- {"irrvariaSSaHH", Attribute::kUndefined},
- {"lkkcin", Attribute::kUndefined},
- {"gjctRRo", Attribute::kUndefined},
- {"lcbton", Attribute::kUndefined},
- {"mustjuse", Attribute::kUndefined},
- {"must_se", Attribute::kUndefined},
- {"muquse", Attribute::kUndefined},
- {"szNN", Attribute::kUndefined},
- {"zvv", Attribute::kUndefined},
- {"QQze", Attribute::kUndefined},
- {"eterf", Attribute::kUndefined},
- {"vertjx", Attribute::kUndefined},
- {"v82wNNx", Attribute::kUndefined},
- {"worgroup_size", Attribute::kUndefined},
- {"workgrourr_size", Attribute::kUndefined},
- {"workgroGp_size", Attribute::kUndefined},
+ {"covior", Attribute::kUndefined},
+ {"co8WWr", Attribute::kUndefined},
+ {"Mxxlo", Attribute::kUndefined},
+ {"cXputgg", Attribute::kUndefined},
+ {"opuXe", Attribute::kUndefined},
+ {"comp3te", Attribute::kUndefined},
+ {"diagnostiE", Attribute::kUndefined},
+ {"TTiagnosPPi", Attribute::kUndefined},
+ {"diagdoxxtic", Attribute::kUndefined},
+ {"44ragment", Attribute::kUndefined},
+ {"fSSagmenVV", Attribute::kUndefined},
+ {"Rag2Rent", Attribute::kUndefined},
+ {"gFup", Attribute::kUndefined},
+ {"grop", Attribute::kUndefined},
+ {"ROOHVp", Attribute::kUndefined},
+ {"y", Attribute::kUndefined},
+ {"Gn77rl", Attribute::kUndefined},
+ {"04d", Attribute::kUndefined},
+ {"oox", Attribute::kUndefined},
+ {"inzz", Attribute::kUndefined},
+ {"1ippex", Attribute::kUndefined},
+ {"interpoXXate", Attribute::kUndefined},
+ {"intII99r55olate", Attribute::kUndefined},
+ {"intaarpoSSrHHYe", Attribute::kUndefined},
+ {"kkvHant", Attribute::kUndefined},
+ {"jgaianRR", Attribute::kUndefined},
+ {"inaianb", Attribute::kUndefined},
+ {"locajion", Attribute::kUndefined},
+ {"locaton", Attribute::kUndefined},
+ {"loqion", Attribute::kUndefined},
+ {"mustusNN", Attribute::kUndefined},
+ {"usvvuse", Attribute::kUndefined},
+ {"mut_QQse", Attribute::kUndefined},
+ {"srf", Attribute::kUndefined},
+ {"sije", Attribute::kUndefined},
+ {"NNz2w", Attribute::kUndefined},
+ {"vrtex", Attribute::kUndefined},
+ {"rrertex", Attribute::kUndefined},
+ {"vGrtex", Attribute::kUndefined},
+ {"workgroup_sizFF", Attribute::kUndefined},
+ {"wErkrp_size", Attribute::kUndefined},
+ {"worgrroup_size", Attribute::kUndefined},
};
using AttributeParseTest = testing::TestWithParam<Case>;
diff --git a/src/tint/lang/core/core.def b/src/tint/lang/core/core.def
index 4e8ced4..2337b79 100644
--- a/src/tint/lang/core/core.def
+++ b/src/tint/lang/core/core.def
@@ -212,6 +212,9 @@
size
vertex
workgroup_size
+
+ // framebuffer-fetch input
+ color
}
////////////////////////////////////////////////////////////////////////////////
diff --git a/src/tint/lang/wgsl/ast/BUILD.bazel b/src/tint/lang/wgsl/ast/BUILD.bazel
index 31601b6..f7514c9 100644
--- a/src/tint/lang/wgsl/ast/BUILD.bazel
+++ b/src/tint/lang/wgsl/ast/BUILD.bazel
@@ -57,6 +57,7 @@
"case_selector.cc",
"case_statement.cc",
"clone_context.cc",
+ "color_attribute.cc",
"compound_assignment_statement.cc",
"const.cc",
"const_assert.cc",
@@ -137,6 +138,7 @@
"case_selector.h",
"case_statement.h",
"clone_context.h",
+ "color_attribute.h",
"compound_assignment_statement.h",
"const.h",
"const_assert.h",
@@ -244,6 +246,7 @@
"case_selector_test.cc",
"case_statement_test.cc",
"clone_context_test.cc",
+ "color_attribute_test.cc",
"compound_assignment_statement_test.cc",
"const_assert_test.cc",
"continue_statement_test.cc",
diff --git a/src/tint/lang/wgsl/ast/BUILD.cmake b/src/tint/lang/wgsl/ast/BUILD.cmake
index ebad7e9..fe4eef9 100644
--- a/src/tint/lang/wgsl/ast/BUILD.cmake
+++ b/src/tint/lang/wgsl/ast/BUILD.cmake
@@ -77,6 +77,8 @@
lang/wgsl/ast/case_statement.h
lang/wgsl/ast/clone_context.cc
lang/wgsl/ast/clone_context.h
+ lang/wgsl/ast/color_attribute.cc
+ lang/wgsl/ast/color_attribute.h
lang/wgsl/ast/compound_assignment_statement.cc
lang/wgsl/ast/compound_assignment_statement.h
lang/wgsl/ast/const.cc
@@ -244,6 +246,7 @@
lang/wgsl/ast/case_selector_test.cc
lang/wgsl/ast/case_statement_test.cc
lang/wgsl/ast/clone_context_test.cc
+ lang/wgsl/ast/color_attribute_test.cc
lang/wgsl/ast/compound_assignment_statement_test.cc
lang/wgsl/ast/const_assert_test.cc
lang/wgsl/ast/continue_statement_test.cc
diff --git a/src/tint/lang/wgsl/ast/BUILD.gn b/src/tint/lang/wgsl/ast/BUILD.gn
index 4580e46..6cc263d 100644
--- a/src/tint/lang/wgsl/ast/BUILD.gn
+++ b/src/tint/lang/wgsl/ast/BUILD.gn
@@ -80,6 +80,8 @@
"case_statement.h",
"clone_context.cc",
"clone_context.h",
+ "color_attribute.cc",
+ "color_attribute.h",
"compound_assignment_statement.cc",
"compound_assignment_statement.h",
"const.cc",
@@ -244,6 +246,7 @@
"case_selector_test.cc",
"case_statement_test.cc",
"clone_context_test.cc",
+ "color_attribute_test.cc",
"compound_assignment_statement_test.cc",
"const_assert_test.cc",
"continue_statement_test.cc",
diff --git a/src/tint/lang/wgsl/ast/builder.h b/src/tint/lang/wgsl/ast/builder.h
index 1cbdfba..1b80ec9 100644
--- a/src/tint/lang/wgsl/ast/builder.h
+++ b/src/tint/lang/wgsl/ast/builder.h
@@ -67,6 +67,7 @@
#include "src/tint/lang/wgsl/ast/call_expression.h"
#include "src/tint/lang/wgsl/ast/call_statement.h"
#include "src/tint/lang/wgsl/ast/case_statement.h"
+#include "src/tint/lang/wgsl/ast/color_attribute.h"
#include "src/tint/lang/wgsl/ast/compound_assignment_statement.h"
#include "src/tint/lang/wgsl/ast/const.h"
#include "src/tint/lang/wgsl/ast/const_assert.h"
@@ -3167,6 +3168,23 @@
return create<ast::LocationAttribute>(source, Expr(std::forward<EXPR>(location)));
}
+ /// Creates an ast::ColorAttribute
+ /// @param index the index value expression
+ /// @returns the index attribute pointer
+ template <typename EXPR>
+ const ast::ColorAttribute* Color(EXPR&& index) {
+ return create<ast::ColorAttribute>(source_, Expr(std::forward<EXPR>(index)));
+ }
+
+ /// Creates an ast::ColorAttribute
+ /// @param source the source information
+ /// @param index the index value expression
+ /// @returns the index attribute pointer
+ template <typename EXPR>
+ const ast::ColorAttribute* Color(const Source& source, EXPR&& index) {
+ return create<ast::ColorAttribute>(source, Expr(std::forward<EXPR>(index)));
+ }
+
/// Creates an ast::LocationAttribute
/// @param location the location value expression
/// @returns the location attribute pointer
diff --git a/src/tint/lang/wgsl/ast/color_attribute.cc b/src/tint/lang/wgsl/ast/color_attribute.cc
new file mode 100644
index 0000000..daa1597
--- /dev/null
+++ b/src/tint/lang/wgsl/ast/color_attribute.cc
@@ -0,0 +1,60 @@
+// Copyright 2023 The Dawn & Tint Authors
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "src/tint/lang/wgsl/ast/color_attribute.h"
+
+#include <string>
+
+#include "src/tint/lang/wgsl/ast/builder.h"
+#include "src/tint/lang/wgsl/ast/clone_context.h"
+
+TINT_INSTANTIATE_TYPEINFO(tint::ast::ColorAttribute);
+
+namespace tint::ast {
+
+ColorAttribute::ColorAttribute(GenerationID pid,
+ NodeID nid,
+ const Source& src,
+ const Expression* exp)
+ : Base(pid, nid, src), expr(exp) {
+ TINT_ASSERT_GENERATION_IDS_EQUAL(exp, generation_id);
+}
+
+ColorAttribute::~ColorAttribute() = default;
+
+std::string ColorAttribute::Name() const {
+ return "color";
+}
+
+const ColorAttribute* ColorAttribute::Clone(CloneContext& ctx) const {
+ // Clone arguments outside of create() call to have deterministic ordering
+ auto src = ctx.Clone(source);
+ auto e = ctx.Clone(expr);
+ return ctx.dst->create<ColorAttribute>(src, e);
+}
+
+} // namespace tint::ast
diff --git a/src/tint/lang/wgsl/ast/color_attribute.h b/src/tint/lang/wgsl/ast/color_attribute.h
new file mode 100644
index 0000000..d0a21e4
--- /dev/null
+++ b/src/tint/lang/wgsl/ast/color_attribute.h
@@ -0,0 +1,68 @@
+// Copyright 2023 The Dawn & Tint Authors
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef SRC_TINT_LANG_WGSL_AST_COLOR_ATTRIBUTE_H_
+#define SRC_TINT_LANG_WGSL_AST_COLOR_ATTRIBUTE_H_
+
+#include <string>
+
+#include "src/tint/lang/wgsl/ast/attribute.h"
+
+// Forward declarations
+namespace tint::ast {
+class Expression;
+}
+
+namespace tint::ast {
+
+/// A color attribute (enabled with the frame-buffer fetch extension)
+class ColorAttribute final : public Castable<ColorAttribute, Attribute> {
+ public:
+ /// constructor
+ /// @param pid the identifier of the program that owns this node
+ /// @param nid the unique node identifier
+ /// @param src the source of this node
+ /// @param expr the frame-buffer index value
+ ColorAttribute(GenerationID pid, NodeID nid, const Source& src, const Expression* expr);
+ ~ColorAttribute() override;
+
+ /// @returns the WGSL name for the attribute
+ std::string Name() const override;
+
+ /// Clones this node and all transitive child nodes using the `CloneContext`
+ /// `ctx`.
+ /// @param ctx the clone context
+ /// @return the newly cloned node
+ const ColorAttribute* Clone(CloneContext& ctx) const override;
+
+ /// The index value expression
+ const Expression* const expr;
+};
+
+} // namespace tint::ast
+
+#endif // SRC_TINT_LANG_WGSL_AST_COLOR_ATTRIBUTE_H_
diff --git a/src/tint/lang/wgsl/ast/color_attribute_test.cc b/src/tint/lang/wgsl/ast/color_attribute_test.cc
new file mode 100644
index 0000000..9afba5f
--- /dev/null
+++ b/src/tint/lang/wgsl/ast/color_attribute_test.cc
@@ -0,0 +1,66 @@
+// Copyright 2023 The Dawn & Tint Authors
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "gtest/gtest-spi.h"
+
+#include "src/tint/lang/wgsl/ast/color_attribute.h"
+#include "src/tint/lang/wgsl/ast/helper_test.h"
+
+using namespace tint::core::number_suffixes; // NOLINT
+
+namespace tint::ast {
+namespace {
+
+using ColorAttributeTest = TestHelper;
+
+TEST_F(ColorAttributeTest, Creation) {
+ auto* expr = Expr(1_u);
+ auto* c = Color(expr);
+ EXPECT_EQ(c->expr, expr);
+}
+
+TEST_F(ColorAttributeTest, Assert_Null_Builtin) {
+ EXPECT_FATAL_FAILURE(
+ {
+ ProgramBuilder b;
+ b.Color(nullptr);
+ },
+ "internal compiler error");
+}
+
+TEST_F(ColorAttributeTest, Assert_DifferentGenerationID_Color) {
+ EXPECT_FATAL_FAILURE(
+ {
+ ProgramBuilder b1;
+ ProgramBuilder b2;
+ b1.Color(b2.Expr(1_u));
+ },
+ "internal compiler error");
+}
+
+} // namespace
+} // namespace tint::ast
diff --git a/src/tint/lang/wgsl/reader/parser/error_resync_test.cc b/src/tint/lang/wgsl/reader/parser/error_resync_test.cc
index 0a368a9..a38fd87 100644
--- a/src/tint/lang/wgsl/reader/parser/error_resync_test.cc
+++ b/src/tint/lang/wgsl/reader/parser/error_resync_test.cc
@@ -67,7 +67,7 @@
^
test.wgsl:4:2 error: expected attribute
-Possible values: 'align', 'binding', 'builtin', 'compute', 'diagnostic', 'fragment', 'group', 'id', 'index', 'interpolate', 'invariant', 'location', 'must_use', 'size', 'vertex', 'workgroup_size'
+Possible values: 'align', 'binding', 'builtin', 'color', 'compute', 'diagnostic', 'fragment', 'group', 'id', 'index', 'interpolate', 'invariant', 'location', 'must_use', 'size', 'vertex', 'workgroup_size'
@_ fn -> {}
^
)");
@@ -135,7 +135,7 @@
^^^^
test.wgsl:7:6 error: expected attribute
-Possible values: 'align', 'binding', 'builtin', 'compute', 'diagnostic', 'fragment', 'group', 'id', 'index', 'interpolate', 'invariant', 'location', 'must_use', 'size', 'vertex', 'workgroup_size'
+Possible values: 'align', 'binding', 'builtin', 'color', 'compute', 'diagnostic', 'fragment', 'group', 'id', 'index', 'interpolate', 'invariant', 'location', 'must_use', 'size', 'vertex', 'workgroup_size'
@- x : i32,
^
)");
diff --git a/src/tint/lang/wgsl/reader/parser/function_attribute_list_test.cc b/src/tint/lang/wgsl/reader/parser/function_attribute_list_test.cc
index 259f1a1..4fae501 100644
--- a/src/tint/lang/wgsl/reader/parser/function_attribute_list_test.cc
+++ b/src/tint/lang/wgsl/reader/parser/function_attribute_list_test.cc
@@ -66,7 +66,7 @@
EXPECT_TRUE(attrs.value.IsEmpty());
EXPECT_EQ(p->error(), R"(1:2: expected attribute
Did you mean 'invariant'?
-Possible values: 'align', 'binding', 'builtin', 'compute', 'diagnostic', 'fragment', 'group', 'id', 'index', 'interpolate', 'invariant', 'location', 'must_use', 'size', 'vertex', 'workgroup_size')");
+Possible values: 'align', 'binding', 'builtin', 'color', 'compute', 'diagnostic', 'fragment', 'group', 'id', 'index', 'interpolate', 'invariant', 'location', 'must_use', 'size', 'vertex', 'workgroup_size')");
}
} // namespace
diff --git a/src/tint/lang/wgsl/reader/parser/variable_attribute_list_test.cc b/src/tint/lang/wgsl/reader/parser/variable_attribute_list_test.cc
index f10f725..417ab1f 100644
--- a/src/tint/lang/wgsl/reader/parser/variable_attribute_list_test.cc
+++ b/src/tint/lang/wgsl/reader/parser/variable_attribute_list_test.cc
@@ -64,7 +64,7 @@
EXPECT_TRUE(attrs.value.IsEmpty());
EXPECT_EQ(p->error(), R"(1:2: expected attribute
Did you mean 'invariant'?
-Possible values: 'align', 'binding', 'builtin', 'compute', 'diagnostic', 'fragment', 'group', 'id', 'index', 'interpolate', 'invariant', 'location', 'must_use', 'size', 'vertex', 'workgroup_size')");
+Possible values: 'align', 'binding', 'builtin', 'color', 'compute', 'diagnostic', 'fragment', 'group', 'id', 'index', 'interpolate', 'invariant', 'location', 'must_use', 'size', 'vertex', 'workgroup_size')");
}
} // namespace