validator: Disallow [[override]] on non-const vars

Only allow them on constants, where no other decoration is valid.

Change-Id: I83f19667adb1dd4ebbba86827324a45a8f1a80a4
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/50041
Auto-Submit: James Price <jrprice@google.com>
Reviewed-by: Ben Clayton <bclayton@google.com>
Commit-Queue: James Price <jrprice@google.com>
diff --git a/src/resolver/decoration_validation_test.cc b/src/resolver/decoration_validation_test.cc
index 1ff15c5..be3926e 100644
--- a/src/resolver/decoration_validation_test.cc
+++ b/src/resolver/decoration_validation_test.cc
@@ -34,9 +34,9 @@
   kAlign,
   kBinding,
   kBuiltin,
-  kConstantId,
   kGroup,
   kLocation,
+  kOverride,
   kOffset,
   kSize,
   kStage,
@@ -63,12 +63,12 @@
       return builder.create<ast::BindingDecoration>(source, 1);
     case DecorationKind::kBuiltin:
       return builder.Builtin(source, ast::Builtin::kPosition);
-    case DecorationKind::kConstantId:
-      return builder.create<ast::OverrideDecoration>(source, 0u);
     case DecorationKind::kGroup:
       return builder.create<ast::GroupDecoration>(source, 1u);
     case DecorationKind::kLocation:
       return builder.Location(source, 1);
+    case DecorationKind::kOverride:
+      return builder.create<ast::OverrideDecoration>(source, 0u);
     case DecorationKind::kOffset:
       return builder.create<ast::StructMemberOffsetDecoration>(source, 4u);
     case DecorationKind::kSize:
@@ -108,9 +108,9 @@
                     TestParams{DecorationKind::kAlign, false},
                     TestParams{DecorationKind::kBinding, false},
                     TestParams{DecorationKind::kBuiltin, true},
-                    TestParams{DecorationKind::kConstantId, false},
                     TestParams{DecorationKind::kGroup, false},
                     TestParams{DecorationKind::kLocation, true},
+                    TestParams{DecorationKind::kOverride, false},
                     TestParams{DecorationKind::kOffset, false},
                     TestParams{DecorationKind::kSize, false},
                     TestParams{DecorationKind::kStage, false},
@@ -150,9 +150,9 @@
                     TestParams{DecorationKind::kAlign, false},
                     TestParams{DecorationKind::kBinding, false},
                     TestParams{DecorationKind::kBuiltin, false},
-                    TestParams{DecorationKind::kConstantId, false},
                     TestParams{DecorationKind::kGroup, false},
                     TestParams{DecorationKind::kLocation, false},
+                    TestParams{DecorationKind::kOverride, false},
                     TestParams{DecorationKind::kOffset, false},
                     TestParams{DecorationKind::kSize, false},
                     TestParams{DecorationKind::kStage, false},
@@ -184,9 +184,9 @@
                     TestParams{DecorationKind::kAlign, false},
                     TestParams{DecorationKind::kBinding, false},
                     TestParams{DecorationKind::kBuiltin, false},
-                    TestParams{DecorationKind::kConstantId, false},
                     TestParams{DecorationKind::kGroup, false},
                     TestParams{DecorationKind::kLocation, false},
+                    TestParams{DecorationKind::kOverride, false},
                     TestParams{DecorationKind::kOffset, false},
                     TestParams{DecorationKind::kSize, false},
                     TestParams{DecorationKind::kStage, false},
@@ -222,9 +222,9 @@
                     TestParams{DecorationKind::kAlign, true},
                     TestParams{DecorationKind::kBinding, false},
                     TestParams{DecorationKind::kBuiltin, true},
-                    TestParams{DecorationKind::kConstantId, false},
                     TestParams{DecorationKind::kGroup, false},
                     TestParams{DecorationKind::kLocation, true},
+                    TestParams{DecorationKind::kOverride, false},
                     TestParams{DecorationKind::kOffset, true},
                     TestParams{DecorationKind::kSize, true},
                     TestParams{DecorationKind::kStage, false},
@@ -257,9 +257,44 @@
                     TestParams{DecorationKind::kAlign, false},
                     TestParams{DecorationKind::kBinding, true},
                     TestParams{DecorationKind::kBuiltin, true},
-                    TestParams{DecorationKind::kConstantId, true},
                     TestParams{DecorationKind::kGroup, true},
                     TestParams{DecorationKind::kLocation, true},
+                    TestParams{DecorationKind::kOverride, false},
+                    TestParams{DecorationKind::kOffset, false},
+                    TestParams{DecorationKind::kSize, false},
+                    TestParams{DecorationKind::kStage, false},
+                    TestParams{DecorationKind::kStride, false},
+                    TestParams{DecorationKind::kStructBlock, false},
+                    TestParams{DecorationKind::kWorkgroup, false}));
+
+using ConstantDecorationTest = TestWithParams;
+TEST_P(ConstantDecorationTest, IsValid) {
+  auto& params = GetParam();
+
+  GlobalConst("a", ty.f32(), nullptr,
+              ast::DecorationList{
+                  createDecoration(Source{{12, 34}}, *this, params.kind)});
+
+  WrapInFunction();
+
+  if (params.should_pass) {
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
+  } else {
+    EXPECT_FALSE(r()->Resolve()) << r()->error();
+    EXPECT_EQ(r()->error(),
+              "12:34 error: decoration is not valid for constants");
+  }
+}
+INSTANTIATE_TEST_SUITE_P(
+    ResolverDecorationValidationTest,
+    ConstantDecorationTest,
+    testing::Values(TestParams{DecorationKind::kAccess, false},
+                    TestParams{DecorationKind::kAlign, false},
+                    TestParams{DecorationKind::kBinding, false},
+                    TestParams{DecorationKind::kBuiltin, false},
+                    TestParams{DecorationKind::kGroup, false},
+                    TestParams{DecorationKind::kLocation, false},
+                    TestParams{DecorationKind::kOverride, true},
                     TestParams{DecorationKind::kOffset, false},
                     TestParams{DecorationKind::kSize, false},
                     TestParams{DecorationKind::kStage, false},
@@ -291,9 +326,9 @@
                     TestParams{DecorationKind::kAlign, false},
                     TestParams{DecorationKind::kBinding, false},
                     TestParams{DecorationKind::kBuiltin, false},
-                    TestParams{DecorationKind::kConstantId, false},
                     TestParams{DecorationKind::kGroup, false},
                     TestParams{DecorationKind::kLocation, false},
+                    TestParams{DecorationKind::kOverride, false},
                     TestParams{DecorationKind::kOffset, false},
                     TestParams{DecorationKind::kSize, false},
                     // Skip kStage as we always apply it in this test
diff --git a/src/resolver/resolver.cc b/src/resolver/resolver.cc
index 603f3dd..8d3f35f 100644
--- a/src/resolver/resolver.cc
+++ b/src/resolver/resolver.cc
@@ -501,11 +501,16 @@
 
   for (auto* deco : var->decorations()) {
     Mark(deco);
-    if (!(deco->Is<ast::BindingDecoration>() ||
-          deco->Is<ast::BuiltinDecoration>() ||
-          deco->Is<ast::OverrideDecoration>() ||
-          deco->Is<ast::GroupDecoration>() ||
-          deco->Is<ast::LocationDecoration>())) {
+    if (var->is_const()) {
+      if (!deco->Is<ast::OverrideDecoration>()) {
+        diagnostics_.add_error("decoration is not valid for constants",
+                               deco->source());
+        return false;
+      }
+    } else if (!(deco->Is<ast::BindingDecoration>() ||
+                 deco->Is<ast::BuiltinDecoration>() ||
+                 deco->Is<ast::GroupDecoration>() ||
+                 deco->Is<ast::LocationDecoration>())) {
       diagnostics_.add_error("decoration is not valid for variables",
                              deco->source());
       return false;