validation: location decoration is not valid for compute shaders

Bug: tint:981
Change-Id: I15024e0cf836af4f3ad7a14b8cd51c24fc3cd536
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/58067
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: James Price <jrprice@google.com>
Commit-Queue: James Price <jrprice@google.com>
Auto-Submit: Sarah Mashayekhi <sarahmashay@google.com>
diff --git a/src/resolver/decoration_validation_test.cc b/src/resolver/decoration_validation_test.cc
index 6b893ac..6e9aa0a 100644
--- a/src/resolver/decoration_validation_test.cc
+++ b/src/resolver/decoration_validation_test.cc
@@ -146,7 +146,7 @@
   if (params.should_pass) {
     EXPECT_TRUE(r()->Resolve()) << r()->error();
   } else {
-    EXPECT_FALSE(r()->Resolve()) << r()->error();
+    EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
               "error: decoration is not valid for non-entry point function "
               "parameters");
@@ -184,7 +184,7 @@
   if (params.should_pass) {
     EXPECT_TRUE(r()->Resolve()) << r()->error();
   } else {
-    EXPECT_FALSE(r()->Resolve()) << r()->error();
+    EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
               "error: decoration is not valid for function parameters");
   }
@@ -197,7 +197,8 @@
                     TestParams{DecorationKind::kBuiltin, true},
                     TestParams{DecorationKind::kGroup, false},
                     TestParams{DecorationKind::kInterpolate, true},
-                    TestParams{DecorationKind::kInvariant, false},
+                    // TODO(crbug.com/tint/1008)
+                    // kInvariant tested separately (requires position builtin)
                     TestParams{DecorationKind::kLocation, true},
                     TestParams{DecorationKind::kOverride, false},
                     TestParams{DecorationKind::kOffset, false},
@@ -238,6 +239,19 @@
   EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
+TEST_F(EntryPointParameterDecorationTest, ComputeShaderLocation) {
+  auto* input = Param("input", ty.vec4<f32>(),
+                      ast::DecorationList{Location(Source{{12, 34}}, 1)});
+  Func("main", {input}, ty.void_(), {},
+       {Stage(ast::PipelineStage::kCompute),
+        create<ast::WorkgroupDecoration>(Source{{12, 34}}, Expr(1))});
+
+  EXPECT_FALSE(r()->Resolve());
+  EXPECT_EQ(r()->error(),
+            "12:34 error: decoration is not valid for compute shader function "
+            "parameters");
+}
+
 using FunctionReturnTypeDecorationTest = TestWithParams;
 TEST_P(FunctionReturnTypeDecorationTest, IsValid) {
   auto& params = GetParam();
@@ -248,7 +262,7 @@
   if (params.should_pass) {
     EXPECT_TRUE(r()->Resolve()) << r()->error();
   } else {
-    EXPECT_FALSE(r()->Resolve()) << r()->error();
+    EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
               "error: decoration is not valid for non-entry point function "
               "return types");
@@ -285,9 +299,16 @@
   if (params.should_pass) {
     EXPECT_TRUE(r()->Resolve()) << r()->error();
   } else {
-    EXPECT_FALSE(r()->Resolve()) << r()->error();
-    EXPECT_EQ(r()->error(),
-              "error: decoration is not valid for entry point return types");
+    EXPECT_FALSE(r()->Resolve());
+    if (params.kind == DecorationKind::kLocation ||
+        params.kind == DecorationKind::kInterpolate) {
+      EXPECT_EQ(r()->error(),
+                "error: decoration is not valid for compute shader entry point "
+                "return types");
+    } else {
+      EXPECT_EQ(r()->error(),
+                "error: decoration is not valid for entry point return types");
+    }
   }
 }
 
@@ -298,9 +319,9 @@
                     TestParams{DecorationKind::kBinding, false},
                     TestParams{DecorationKind::kBuiltin, true},
                     TestParams{DecorationKind::kGroup, false},
-                    TestParams{DecorationKind::kInterpolate, true},
+                    TestParams{DecorationKind::kInterpolate, false},
                     // kInvariant tested separately (requires position builtin)
-                    TestParams{DecorationKind::kLocation, true},
+                    TestParams{DecorationKind::kLocation, false},
                     TestParams{DecorationKind::kOverride, false},
                     TestParams{DecorationKind::kOffset, false},
                     TestParams{DecorationKind::kSize, false},
@@ -367,7 +388,7 @@
   if (params.should_pass) {
     EXPECT_TRUE(r()->Resolve()) << r()->error();
   } else {
-    EXPECT_FALSE(r()->Resolve()) << r()->error();
+    EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
               "12:34 error: decoration is not valid for array types");
   }
@@ -403,7 +424,7 @@
   if (params.should_pass) {
     EXPECT_TRUE(r()->Resolve()) << r()->error();
   } else {
-    EXPECT_FALSE(r()->Resolve()) << r()->error();
+    EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
               "12:34 error: decoration is not valid for struct declarations");
   }
@@ -467,7 +488,7 @@
   if (params.should_pass) {
     EXPECT_TRUE(r()->Resolve()) << r()->error();
   } else {
-    EXPECT_FALSE(r()->Resolve()) << r()->error();
+    EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
               "12:34 error: decoration is not valid for structure members");
   }
@@ -528,7 +549,7 @@
   if (params.should_pass) {
     EXPECT_TRUE(r()->Resolve()) << r()->error();
   } else {
-    EXPECT_FALSE(r()->Resolve()) << r()->error();
+    EXPECT_FALSE(r()->Resolve());
     if (!IsBindingDecoration(params.kind)) {
       EXPECT_EQ(r()->error(),
                 "12:34 error: decoration is not valid for variables");
@@ -582,7 +603,7 @@
   if (params.should_pass) {
     EXPECT_TRUE(r()->Resolve()) << r()->error();
   } else {
-    EXPECT_FALSE(r()->Resolve()) << r()->error();
+    EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
               "12:34 error: decoration is not valid for constants");
   }
@@ -632,7 +653,7 @@
   if (params.should_pass) {
     EXPECT_TRUE(r()->Resolve()) << r()->error();
   } else {
-    EXPECT_FALSE(r()->Resolve()) << r()->error();
+    EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
               "12:34 error: decoration is not valid for functions");
   }
diff --git a/src/resolver/resolver.cc b/src/resolver/resolver.cc
index 604972b..dd37815 100644
--- a/src/resolver/resolver.cc
+++ b/src/resolver/resolver.cc
@@ -1165,7 +1165,14 @@
       if (!ValidateInterpolateDecoration(interpolate, info->type)) {
         return false;
       }
-    } else if (!deco->IsAnyOf<ast::LocationDecoration, ast::BuiltinDecoration,
+    } else if (deco->Is<ast::LocationDecoration>()) {
+      if (func->pipeline_stage() == ast::PipelineStage::kCompute) {
+        AddError(
+            "decoration is not valid for compute shader function parameters",
+            deco->source());
+        return false;
+      }
+    } else if (!deco->IsAnyOf<ast::BuiltinDecoration,
                               ast::InternalDecoration>() &&
                (IsValidationEnabled(
                     info->declaration->decorations(),
@@ -1421,9 +1428,16 @@
         if (!ValidateInterpolateDecoration(interpolate, info->return_type)) {
           return false;
         }
-      } else if (!deco->IsAnyOf<ast::LocationDecoration, ast::BuiltinDecoration,
-                                ast::InvariantDecoration,
-                                ast::InternalDecoration>() &&
+      } else if (deco->Is<ast::LocationDecoration>()) {
+        if (func->pipeline_stage() == ast::PipelineStage::kCompute) {
+          AddError(
+              "decoration is not valid for compute shader entry point return "
+              "types",
+              deco->source());
+          return false;
+        }
+      } else if (!deco->IsAnyOf<ast::BuiltinDecoration, ast::InternalDecoration,
+                                ast::InvariantDecoration>() &&
                  (IsValidationEnabled(
                       info->declaration->decorations(),
                       ast::DisabledValidation::kEntryPointParameter) &&