tint: Add StructMember attributes to sem.

Removes the need to examine AST attributes.

Change-Id: Iaaa6b10fd56baf732057c4c3960c1bfc5bbdeaa6
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/129621
Reviewed-by: Dan Sinclair <dsinclair@chromium.org>
Commit-Queue: Dan Sinclair <dsinclair@chromium.org>
Kokoro: Kokoro <noreply+kokoro@google.com>
diff --git a/src/tint/writer/hlsl/generator_impl.cc b/src/tint/writer/hlsl/generator_impl.cc
index 5cce6a1..1d19efe 100644
--- a/src/tint/writer/hlsl/generator_impl.cc
+++ b/src/tint/writer/hlsl/generator_impl.cc
@@ -4216,73 +4216,48 @@
             auto* ty = mem->Type();
             auto out = line(b);
             std::string pre, post;
-            if (auto* decl = mem->Declaration()) {
-                for (auto* attr : decl->attributes) {
-                    if (attr->Is<ast::LocationAttribute>()) {
-                        auto& pipeline_stage_uses = str->PipelineStageUses();
-                        if (TINT_UNLIKELY(pipeline_stage_uses.size() != 1)) {
-                            TINT_ICE(Writer, diagnostics_) << "invalid entry point IO struct uses";
-                        }
 
-                        auto loc = mem->Location().value();
-                        if (pipeline_stage_uses.count(type::PipelineStageUsage::kVertexInput)) {
-                            post += " : TEXCOORD" + std::to_string(loc);
-                        } else if (pipeline_stage_uses.count(
-                                       type::PipelineStageUsage::kVertexOutput)) {
-                            post += " : TEXCOORD" + std::to_string(loc);
-                        } else if (pipeline_stage_uses.count(
-                                       type::PipelineStageUsage::kFragmentInput)) {
-                            post += " : TEXCOORD" + std::to_string(loc);
-                        } else if (TINT_LIKELY(pipeline_stage_uses.count(
-                                       type::PipelineStageUsage::kFragmentOutput))) {
-                            post += " : SV_Target" + std::to_string(loc);
-                        } else {
-                            TINT_ICE(Writer, diagnostics_) << "invalid use of location attribute";
-                        }
-                    } else if (auto* builtin_attr = attr->As<ast::BuiltinAttribute>()) {
-                        auto builtin = program_->Sem().Get(builtin_attr)->Value();
-                        auto name = builtin_to_attribute(builtin);
-                        if (name.empty()) {
-                            diagnostics_.add_error(diag::System::Writer, "unsupported builtin");
-                            return false;
-                        }
-                        post += " : " + name;
-                    } else if (auto* interpolate = attr->As<ast::InterpolateAttribute>()) {
-                        auto& sem = program_->Sem();
-                        auto i_type =
-                            sem.Get<sem::BuiltinEnumExpression<builtin::InterpolationType>>(
-                                   interpolate->type)
-                                ->Value();
+            auto& attributes = mem->Attributes();
 
-                        auto i_smpl = builtin::InterpolationSampling::kUndefined;
-                        if (interpolate->sampling) {
-                            i_smpl =
-                                sem.Get<sem::BuiltinEnumExpression<builtin::InterpolationSampling>>(
-                                       interpolate->sampling)
-                                    ->Value();
-                        }
-
-                        auto mod = interpolation_to_modifiers(i_type, i_smpl);
-                        if (mod.empty()) {
-                            diagnostics_.add_error(diag::System::Writer,
-                                                   "unsupported interpolation");
-                            return false;
-                        }
-                        pre += mod;
-
-                    } else if (attr->Is<ast::InvariantAttribute>()) {
-                        // Note: `precise` is not exactly the same as `invariant`, but is
-                        // stricter and therefore provides the necessary guarantees.
-                        // See discussion here: https://github.com/gpuweb/gpuweb/issues/893
-                        pre += "precise ";
-                    } else if (TINT_UNLIKELY((!attr->IsAnyOf<ast::StructMemberAlignAttribute,
-                                                             ast::StructMemberOffsetAttribute,
-                                                             ast::StructMemberSizeAttribute>()))) {
-                        TINT_ICE(Writer, diagnostics_)
-                            << "unhandled struct member attribute: " << attr->Name();
-                        return false;
-                    }
+            if (auto location = attributes.location) {
+                auto& pipeline_stage_uses = str->PipelineStageUses();
+                if (TINT_UNLIKELY(pipeline_stage_uses.size() != 1)) {
+                    TINT_ICE(Writer, diagnostics_) << "invalid entry point IO struct uses";
                 }
+                if (pipeline_stage_uses.count(type::PipelineStageUsage::kVertexInput)) {
+                    post += " : TEXCOORD" + std::to_string(location.value());
+                } else if (pipeline_stage_uses.count(type::PipelineStageUsage::kVertexOutput)) {
+                    post += " : TEXCOORD" + std::to_string(location.value());
+                } else if (pipeline_stage_uses.count(type::PipelineStageUsage::kFragmentInput)) {
+                    post += " : TEXCOORD" + std::to_string(location.value());
+                } else if (TINT_LIKELY(pipeline_stage_uses.count(
+                               type::PipelineStageUsage::kFragmentOutput))) {
+                    post += " : SV_Target" + std::to_string(location.value());
+                } else {
+                    TINT_ICE(Writer, diagnostics_) << "invalid use of location attribute";
+                }
+            }
+            if (auto builtin = attributes.builtin) {
+                auto name = builtin_to_attribute(builtin.value());
+                if (name.empty()) {
+                    diagnostics_.add_error(diag::System::Writer, "unsupported builtin");
+                    return false;
+                }
+                post += " : " + name;
+            }
+            if (auto interpolation = attributes.interpolation) {
+                auto mod = interpolation_to_modifiers(interpolation->type, interpolation->sampling);
+                if (mod.empty()) {
+                    diagnostics_.add_error(diag::System::Writer, "unsupported interpolation");
+                    return false;
+                }
+                pre += mod;
+            }
+            if (attributes.invariant) {
+                // Note: `precise` is not exactly the same as `invariant`, but is
+                // stricter and therefore provides the necessary guarantees.
+                // See discussion here: https://github.com/gpuweb/gpuweb/issues/893
+                pre += "precise ";
             }
 
             out << pre;