Update DEPRECATED comments about offset decorations

Let's keep these for the SPIR-V reader case. The way things currently work is actually nicer than attempting to generate size / align decorations in the SPIR-V reader.

Change-Id: I83087c153e3b3056e737dcfbfd73ae6a0986bd7c
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/44684
Commit-Queue: Ben Clayton <bclayton@google.com>
Reviewed-by: David Neto <dneto@google.com>
diff --git a/src/ast/struct_member_offset_decoration.h b/src/ast/struct_member_offset_decoration.h
index 3ab806d..b65b784 100644
--- a/src/ast/struct_member_offset_decoration.h
+++ b/src/ast/struct_member_offset_decoration.h
@@ -21,8 +21,15 @@
 namespace ast {
 
 /// A struct member offset decoration
-// [DEPRECATED] - Replaced with StructMemberAlignDecoration and
-// StructMemberSizeDecoration
+/// @note The WGSL spec removed the `[[offset(n)]]` decoration for `[[size(n)]]`
+/// and `[[align(n)]]` in https://github.com/gpuweb/gpuweb/pull/1447. However
+/// this decoration is kept because the SPIR-V reader has to deal with absolute
+/// offsets, and transforming these to size / align is complex and can be done
+/// in a number of ways. The Resolver is responsible for consuming the size and
+/// align decorations and transforming these into absolute offsets. It is
+/// trivial for the Resolver to handle `[[offset(n)]]` or `[[size(n)]]` /
+/// `[[align(n)]]` decorations, so this is what we do, keeping all the layout
+/// logic in one place.
 class StructMemberOffsetDecoration
     : public Castable<StructMemberOffsetDecoration, Decoration> {
  public:
diff --git a/src/resolver/resolver.cc b/src/resolver/resolver.cc
index 405a80b..e1f1301 100644
--- a/src/resolver/resolver.cc
+++ b/src/resolver/resolver.cc
@@ -1155,9 +1155,13 @@
       return nullptr;
     }
 
+    bool has_offset_deco = false;
+    bool has_align_deco = false;
+    bool has_size_deco = false;
     for (auto* deco : member->decorations()) {
       if (auto* o = deco->As<ast::StructMemberOffsetDecoration>()) {
-        // [DEPRECATED]
+        // Offset decorations are not part of the WGSL spec, but are emitted by
+        // the SPIR-V reader.
         if (o->offset() < struct_size) {
           diagnostics_.add_error("offsets must be in ascending order",
                                  o->source());
@@ -1165,6 +1169,7 @@
         }
         offset = o->offset();
         align = 1;
+        has_offset_deco = true;
       } else if (auto* a = deco->As<ast::StructMemberAlignDecoration>()) {
         if (a->align() <= 0 || !utils::IsPowerOfTwo(a->align())) {
           diagnostics_.add_error(
@@ -1173,6 +1178,7 @@
           return nullptr;
         }
         align = a->align();
+        has_align_deco = true;
       } else if (auto* s = deco->As<ast::StructMemberSizeDecoration>()) {
         if (s->size() < size) {
           diagnostics_.add_error(
@@ -1182,9 +1188,17 @@
           return nullptr;
         }
         size = s->size();
+        has_size_deco = true;
       }
     }
 
+    if (has_offset_deco && (has_align_deco || has_size_deco)) {
+      diagnostics_.add_error(
+          "offset decorations cannot be used with align or size decorations",
+          member->source());
+      return nullptr;
+    }
+
     offset = utils::RoundUp(align, offset);
 
     auto* sem_member =
diff --git a/src/resolver/validation_test.cc b/src/resolver/validation_test.cc
index f3d3cbd..02965fe 100644
--- a/src/resolver/validation_test.cc
+++ b/src/resolver/validation_test.cc
@@ -588,6 +588,42 @@
             "12:34 error: size must be at least as big as the type's size (4)");
 }
 
+TEST_F(ResolverValidationTest, OffsetAndSizeDecoration) {
+  Structure("S", {
+                     Member(Source{{12, 34}}, "a", ty.f32(),
+                            {MemberOffset(0), MemberSize(4)}),
+                 });
+
+  EXPECT_FALSE(r()->Resolve());
+  EXPECT_EQ(r()->error(),
+            "12:34 error: offset decorations cannot be used with align or size "
+            "decorations");
+}
+
+TEST_F(ResolverValidationTest, OffsetAndAlignDecoration) {
+  Structure("S", {
+                     Member(Source{{12, 34}}, "a", ty.f32(),
+                            {MemberOffset(0), MemberAlign(4)}),
+                 });
+
+  EXPECT_FALSE(r()->Resolve());
+  EXPECT_EQ(r()->error(),
+            "12:34 error: offset decorations cannot be used with align or size "
+            "decorations");
+}
+
+TEST_F(ResolverValidationTest, OffsetAndAlignAndSizeDecoration) {
+  Structure("S", {
+                     Member(Source{{12, 34}}, "a", ty.f32(),
+                            {MemberOffset(0), MemberAlign(4), MemberSize(4)}),
+                 });
+
+  EXPECT_FALSE(r()->Resolve());
+  EXPECT_EQ(r()->error(),
+            "12:34 error: offset decorations cannot be used with align or size "
+            "decorations");
+}
+
 }  // namespace
 }  // namespace resolver
 }  // namespace tint