tint: Have ast::DiagnosticControl use ast::Identifier

Instead of ast::IdentifierExpression.
The name is not an expression.

Fixed: tint:1257
Change-Id: I3161d20f584bfedf730b9257233f9dfcb064298a
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/118344
Reviewed-by: James Price <jrprice@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
Commit-Queue: Ben Clayton <bclayton@google.com>
Reviewed-by: Dan Sinclair <dsinclair@chromium.org>
Kokoro: Ben Clayton <bclayton@google.com>
diff --git a/src/tint/ast/block_statement_test.cc b/src/tint/ast/block_statement_test.cc
index f88aa4c..5fc7910 100644
--- a/src/tint/ast/block_statement_test.cc
+++ b/src/tint/ast/block_statement_test.cc
@@ -45,8 +45,8 @@
     auto* d = create<DiscardStatement>();
     auto* ptr = d;
 
-    auto* attr1 = DiagnosticAttribute(ast::DiagnosticSeverity::kOff, Expr("foo"));
-    auto* attr2 = DiagnosticAttribute(ast::DiagnosticSeverity::kOff, Expr("bar"));
+    auto* attr1 = DiagnosticAttribute(ast::DiagnosticSeverity::kOff, "foo");
+    auto* attr2 = DiagnosticAttribute(ast::DiagnosticSeverity::kOff, "bar");
     auto* b = create<BlockStatement>(utils::Vector{d}, utils::Vector{attr1, attr2});
 
     ASSERT_EQ(b->statements.Length(), 1u);
diff --git a/src/tint/ast/diagnostic_attribute_test.cc b/src/tint/ast/diagnostic_attribute_test.cc
index d7f0779..7cdeabb 100644
--- a/src/tint/ast/diagnostic_attribute_test.cc
+++ b/src/tint/ast/diagnostic_attribute_test.cc
@@ -21,7 +21,7 @@
 using DiagnosticAttributeTest = TestHelper;
 
 TEST_F(DiagnosticAttributeTest, Creation) {
-    auto* name = Expr("foo");
+    auto* name = Ident("foo");
     auto* d = DiagnosticAttribute(DiagnosticSeverity::kWarning, name);
     EXPECT_EQ(d->Name(), "diagnostic");
     EXPECT_EQ(d->control->severity, DiagnosticSeverity::kWarning);
diff --git a/src/tint/ast/diagnostic_control.h b/src/tint/ast/diagnostic_control.h
index 7b6e28c..d1df329 100644
--- a/src/tint/ast/diagnostic_control.h
+++ b/src/tint/ast/diagnostic_control.h
@@ -31,7 +31,7 @@
 
 // Forward declarations
 namespace tint::ast {
-class IdentifierExpression;
+class Identifier;
 }  // namespace tint::ast
 
 namespace tint::ast {
@@ -103,7 +103,7 @@
                       NodeID nid,
                       const Source& src,
                       DiagnosticSeverity sev,
-                      const IdentifierExpression* rule)
+                      const Identifier* rule)
         : Base(pid, nid, src), severity(sev), rule_name(rule) {}
 
     ~DiagnosticControl() override;
@@ -117,7 +117,7 @@
     DiagnosticSeverity severity;
 
     /// The diagnostic rule name.
-    const IdentifierExpression* rule_name;
+    const Identifier* rule_name;
 };
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/diagnostic_control.h.tmpl b/src/tint/ast/diagnostic_control.h.tmpl
index 49946c2..c106a3e 100644
--- a/src/tint/ast/diagnostic_control.h.tmpl
+++ b/src/tint/ast/diagnostic_control.h.tmpl
@@ -21,7 +21,7 @@
 
 // Forward declarations
 namespace tint::ast {
-class IdentifierExpression;
+class Identifier;
 }  // namespace tint::ast
 
 namespace tint::ast {
@@ -51,7 +51,7 @@
                       NodeID nid,
                       const Source& src,
                       DiagnosticSeverity sev,
-                      const IdentifierExpression* rule)
+                      const Identifier* rule)
         : Base(pid, nid, src), severity(sev), rule_name(rule) {}
 
     ~DiagnosticControl() override;
@@ -65,7 +65,7 @@
     DiagnosticSeverity severity;
 
     /// The diagnostic rule name.
-    const IdentifierExpression* rule_name;
+    const Identifier* rule_name;
 };
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/diagnostic_control_test.cc b/src/tint/ast/diagnostic_control_test.cc
index 11a544a..798d187 100644
--- a/src/tint/ast/diagnostic_control_test.cc
+++ b/src/tint/ast/diagnostic_control_test.cc
@@ -31,7 +31,7 @@
 using DiagnosticControlTest = TestHelper;
 
 TEST_F(DiagnosticControlTest, Creation) {
-    auto* name = Expr("foo");
+    auto* name = Ident("foo");
     Source source;
     source.range.begin = Source::Location{20, 2};
     source.range.end = Source::Location{20, 5};
diff --git a/src/tint/ast/diagnostic_control_test.cc.tmpl b/src/tint/ast/diagnostic_control_test.cc.tmpl
index 2d1a2cc..74ff73e 100644
--- a/src/tint/ast/diagnostic_control_test.cc.tmpl
+++ b/src/tint/ast/diagnostic_control_test.cc.tmpl
@@ -21,7 +21,7 @@
 using DiagnosticControlTest = TestHelper;
 
 TEST_F(DiagnosticControlTest, Creation) {
-    auto* name = Expr("foo");
+    auto* name = Ident("foo");
     Source source;
     source.range.begin = Source::Location{20, 2};
     source.range.end = Source::Location{20, 5};
diff --git a/src/tint/ast/module_test.cc b/src/tint/ast/module_test.cc
index 980645a..457d8ae 100644
--- a/src/tint/ast/module_test.cc
+++ b/src/tint/ast/module_test.cc
@@ -133,9 +133,9 @@
 
 TEST_F(ModuleTest, Directives) {
     auto* enable_1 = Enable(ast::Extension::kF16);
-    auto* diagnostic_1 = DiagnosticDirective(DiagnosticSeverity::kWarning, Expr("foo"));
+    auto* diagnostic_1 = DiagnosticDirective(DiagnosticSeverity::kWarning, "foo");
     auto* enable_2 = Enable(ast::Extension::kChromiumExperimentalFullPtrParameters);
-    auto* diagnostic_2 = DiagnosticDirective(DiagnosticSeverity::kOff, Expr("bar"));
+    auto* diagnostic_2 = DiagnosticDirective(DiagnosticSeverity::kOff, "bar");
 
     this->SetResolveOnBuild(false);
     Program program(std::move(*this));
diff --git a/src/tint/program_builder.h b/src/tint/program_builder.h
index 745656b..4f05bf4 100644
--- a/src/tint/program_builder.h
+++ b/src/tint/program_builder.h
@@ -3280,23 +3280,23 @@
     /// @param severity the diagnostic severity control
     /// @param rule_name the diagnostic rule name
     /// @returns the diagnostic attribute pointer
-    const ast::DiagnosticAttribute* DiagnosticAttribute(
-        const Source& source,
-        ast::DiagnosticSeverity severity,
-        const ast::IdentifierExpression* rule_name) {
-        return create<ast::DiagnosticAttribute>(source,
-                                                DiagnosticControl(source, severity, rule_name));
+    template <typename NAME>
+    const ast::DiagnosticAttribute* DiagnosticAttribute(const Source& source,
+                                                        ast::DiagnosticSeverity severity,
+                                                        NAME&& rule_name) {
+        return create<ast::DiagnosticAttribute>(
+            source, DiagnosticControl(source, severity, std::forward<NAME>(rule_name)));
     }
 
     /// Creates an ast::DiagnosticAttribute
     /// @param severity the diagnostic severity control
     /// @param rule_name the diagnostic rule name
     /// @returns the diagnostic attribute pointer
-    const ast::DiagnosticAttribute* DiagnosticAttribute(
-        ast::DiagnosticSeverity severity,
-        const ast::IdentifierExpression* rule_name) {
-        return create<ast::DiagnosticAttribute>(source_,
-                                                DiagnosticControl(source_, severity, rule_name));
+    template <typename NAME>
+    const ast::DiagnosticAttribute* DiagnosticAttribute(ast::DiagnosticSeverity severity,
+                                                        NAME&& rule_name) {
+        return create<ast::DiagnosticAttribute>(
+            source_, DiagnosticControl(source_, severity, std::forward<NAME>(rule_name)));
     }
 
     /// Creates an ast::DiagnosticControl
@@ -3304,19 +3304,23 @@
     /// @param severity the diagnostic severity control
     /// @param rule_name the diagnostic rule name
     /// @returns the diagnostic control pointer
+    template <typename NAME>
     const ast::DiagnosticControl* DiagnosticControl(const Source& source,
                                                     ast::DiagnosticSeverity severity,
-                                                    const ast::IdentifierExpression* rule_name) {
-        return create<ast::DiagnosticControl>(source, severity, rule_name);
+                                                    NAME&& rule_name) {
+        return create<ast::DiagnosticControl>(source, severity,
+                                              Ident(std::forward<NAME>(rule_name)));
     }
 
     /// Creates an ast::DiagnosticControl
     /// @param severity the diagnostic severity control
     /// @param rule_name the diagnostic rule name
     /// @returns the diagnostic control pointer
+    template <typename NAME>
     const ast::DiagnosticControl* DiagnosticControl(ast::DiagnosticSeverity severity,
-                                                    const ast::IdentifierExpression* rule_name) {
-        return create<ast::DiagnosticControl>(source_, severity, rule_name);
+                                                    NAME&& rule_name) {
+        return create<ast::DiagnosticControl>(source_, severity,
+                                              Ident(std::forward<NAME>(rule_name)));
     }
 
     /// Add a global diagnostic control to the module.
@@ -3324,10 +3328,11 @@
     /// @param severity the diagnostic severity control
     /// @param rule_name the diagnostic rule name
     /// @returns the diagnostic control pointer
+    template <typename NAME>
     const ast::DiagnosticControl* DiagnosticDirective(const Source& source,
                                                       ast::DiagnosticSeverity severity,
-                                                      const ast::IdentifierExpression* rule_name) {
-        auto* control = DiagnosticControl(source, severity, rule_name);
+                                                      NAME&& rule_name) {
+        auto* control = DiagnosticControl(source, severity, Ident(std::forward<NAME>(rule_name)));
         AST().AddDiagnosticControl(control);
         return control;
     }
@@ -3336,9 +3341,10 @@
     /// @param severity the diagnostic severity control
     /// @param rule_name the diagnostic rule name
     /// @returns the diagnostic control pointer
+    template <typename NAME>
     const ast::DiagnosticControl* DiagnosticDirective(ast::DiagnosticSeverity severity,
-                                                      const ast::IdentifierExpression* rule_name) {
-        auto* control = DiagnosticControl(source_, severity, rule_name);
+                                                      NAME&& rule_name) {
+        auto* control = DiagnosticControl(source_, severity, Ident(std::forward<NAME>(rule_name)));
         AST().AddDiagnosticControl(control);
         return control;
     }
diff --git a/src/tint/reader/spirv/parser.cc b/src/tint/reader/spirv/parser.cc
index 41e6df3..be0d238 100644
--- a/src/tint/reader/spirv/parser.cc
+++ b/src/tint/reader/spirv/parser.cc
@@ -41,8 +41,7 @@
     if (options.allow_non_uniform_derivatives) {
         // Suppress errors regarding non-uniform derivative operations if requested, by adding a
         // diagnostic directive to the module.
-        builder.DiagnosticDirective(ast::DiagnosticSeverity::kOff,
-                                    builder.Expr("derivative_uniformity"));
+        builder.DiagnosticDirective(ast::DiagnosticSeverity::kOff, "derivative_uniformity");
     }
 
     // The SPIR-V parser can construct disjoint AST nodes, which is invalid for
diff --git a/src/tint/reader/wgsl/parser_impl.cc b/src/tint/reader/wgsl/parser_impl.cc
index e95ef00..ca1add2 100644
--- a/src/tint/reader/wgsl/parser_impl.cc
+++ b/src/tint/reader/wgsl/parser_impl.cc
@@ -3775,7 +3775,7 @@
         match(Token::Type::kComma);
 
         return create<ast::DiagnosticControl>(source, severity_control.value,
-                                              builder_.Expr(rule_name.source, rule_name.value));
+                                              builder_.Ident(rule_name.source, rule_name.value));
     });
 }
 
diff --git a/src/tint/reader/wgsl/parser_impl_diagnostic_attribute_test.cc b/src/tint/reader/wgsl/parser_impl_diagnostic_attribute_test.cc
index 5f1fe72..74c99d0 100644
--- a/src/tint/reader/wgsl/parser_impl_diagnostic_attribute_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_diagnostic_attribute_test.cc
@@ -27,9 +27,9 @@
     auto* d = a.value->As<ast::DiagnosticAttribute>();
     ASSERT_NE(d, nullptr);
     EXPECT_EQ(d->control->severity, ast::DiagnosticSeverity::kOff);
-    auto* r = As<ast::IdentifierExpression>(d->control->rule_name);
+    auto* r = d->control->rule_name;
     ASSERT_NE(r, nullptr);
-    EXPECT_EQ(p->builder().Symbols().NameFor(r->identifier->symbol), "foo");
+    EXPECT_EQ(p->builder().Symbols().NameFor(r->symbol), "foo");
 }
 
 }  // namespace
diff --git a/src/tint/reader/wgsl/parser_impl_diagnostic_control_test.cc b/src/tint/reader/wgsl/parser_impl_diagnostic_control_test.cc
index 720340f..37abb85 100644
--- a/src/tint/reader/wgsl/parser_impl_diagnostic_control_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_diagnostic_control_test.cc
@@ -32,9 +32,9 @@
     ASSERT_TRUE(e->Is<ast::DiagnosticControl>());
     EXPECT_EQ(e->severity, params.second);
 
-    auto* r = As<ast::IdentifierExpression>(e->rule_name);
+    auto* r = e->rule_name;
     ASSERT_NE(r, nullptr);
-    EXPECT_EQ(p->builder().Symbols().NameFor(r->identifier->symbol), "foo");
+    EXPECT_EQ(p->builder().Symbols().NameFor(r->symbol), "foo");
 }
 INSTANTIATE_TEST_SUITE_P(DiagnosticControlParserTest,
                          DiagnosticControlParserTest,
@@ -52,9 +52,9 @@
     ASSERT_TRUE(e->Is<ast::DiagnosticControl>());
     EXPECT_EQ(e->severity, ast::DiagnosticSeverity::kError);
 
-    auto* r = As<ast::IdentifierExpression>(e->rule_name);
+    auto* r = e->rule_name;
     ASSERT_NE(r, nullptr);
-    EXPECT_EQ(p->builder().Symbols().NameFor(r->identifier->symbol), "foo");
+    EXPECT_EQ(p->builder().Symbols().NameFor(r->symbol), "foo");
 }
 
 TEST_F(ParserImplTest, DiagnosticControl_MissingOpenParen) {
diff --git a/src/tint/reader/wgsl/parser_impl_diagnostic_directive_test.cc b/src/tint/reader/wgsl/parser_impl_diagnostic_directive_test.cc
index 0eb5f7c..6e3be7d 100644
--- a/src/tint/reader/wgsl/parser_impl_diagnostic_directive_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_diagnostic_directive_test.cc
@@ -30,9 +30,9 @@
     ASSERT_EQ(ast.GlobalDeclarations().Length(), 1u);
     EXPECT_EQ(ast.GlobalDeclarations()[0], control);
 
-    auto* r = As<ast::IdentifierExpression>(control->rule_name);
+    auto* r = control->rule_name;
     ASSERT_NE(r, nullptr);
-    EXPECT_EQ(p->builder().Symbols().NameFor(r->identifier->symbol), "foo");
+    EXPECT_EQ(p->builder().Symbols().NameFor(r->symbol), "foo");
 }
 
 TEST_F(ParserImplTest, DiagnosticDirective_MissingSemicolon) {
diff --git a/src/tint/resolver/attribute_validation_test.cc b/src/tint/resolver/attribute_validation_test.cc
index a504068..d5c3e0e 100644
--- a/src/tint/resolver/attribute_validation_test.cc
+++ b/src/tint/resolver/attribute_validation_test.cc
@@ -98,7 +98,7 @@
             return {builder.Builtin(source, ast::BuiltinValue::kPosition)};
         case AttributeKind::kDiagnostic:
             return {builder.DiagnosticAttribute(source, ast::DiagnosticSeverity::kInfo,
-                                                builder.Expr("chromium_unreachable_code"))};
+                                                "chromium_unreachable_code")};
         case AttributeKind::kGroup:
             return {builder.Group(source, 1_a)};
         case AttributeKind::kId:
diff --git a/src/tint/resolver/dependency_graph_test.cc b/src/tint/resolver/dependency_graph_test.cc
index 84b5469..d63f00a 100644
--- a/src/tint/resolver/dependency_graph_test.cc
+++ b/src/tint/resolver/dependency_graph_test.cc
@@ -1097,7 +1097,7 @@
     auto* var_1 = GlobalVar("SYMBOL1", ty.i32());
     auto* enable = Enable(ast::Extension::kF16);
     auto* var_2 = GlobalVar("SYMBOL2", ty.f32());
-    auto* diagnostic = DiagnosticControl(ast::DiagnosticSeverity::kWarning, Expr("foo"));
+    auto* diagnostic = DiagnosticControl(ast::DiagnosticSeverity::kWarning, "foo");
     AST().AddDiagnosticControl(diagnostic);
 
     EXPECT_THAT(AST().GlobalDeclarations(), ElementsAre(var_1, enable, var_2, diagnostic));
diff --git a/src/tint/resolver/diagnostic_control_test.cc b/src/tint/resolver/diagnostic_control_test.cc
index 4cf2b47..d062e9b 100644
--- a/src/tint/resolver/diagnostic_control_test.cc
+++ b/src/tint/resolver/diagnostic_control_test.cc
@@ -32,7 +32,7 @@
 }
 
 TEST_F(ResolverDiagnosticControlTest, UnreachableCode_ErrorViaDirective) {
-    DiagnosticDirective(ast::DiagnosticSeverity::kError, Expr("chromium_unreachable_code"));
+    DiagnosticDirective(ast::DiagnosticSeverity::kError, "chromium_unreachable_code");
 
     auto stmts = utils::Vector{Return(), Return()};
     Func("foo", {}, ty.void_(), stmts);
@@ -42,7 +42,7 @@
 }
 
 TEST_F(ResolverDiagnosticControlTest, UnreachableCode_WarningViaDirective) {
-    DiagnosticDirective(ast::DiagnosticSeverity::kWarning, Expr("chromium_unreachable_code"));
+    DiagnosticDirective(ast::DiagnosticSeverity::kWarning, "chromium_unreachable_code");
 
     auto stmts = utils::Vector{Return(), Return()};
     Func("foo", {}, ty.void_(), stmts);
@@ -52,7 +52,7 @@
 }
 
 TEST_F(ResolverDiagnosticControlTest, UnreachableCode_InfoViaDirective) {
-    DiagnosticDirective(ast::DiagnosticSeverity::kInfo, Expr("chromium_unreachable_code"));
+    DiagnosticDirective(ast::DiagnosticSeverity::kInfo, "chromium_unreachable_code");
 
     auto stmts = utils::Vector{Return(), Return()};
     Func("foo", {}, ty.void_(), stmts);
@@ -62,7 +62,7 @@
 }
 
 TEST_F(ResolverDiagnosticControlTest, UnreachableCode_OffViaDirective) {
-    DiagnosticDirective(ast::DiagnosticSeverity::kOff, Expr("chromium_unreachable_code"));
+    DiagnosticDirective(ast::DiagnosticSeverity::kOff, "chromium_unreachable_code");
 
     auto stmts = utils::Vector{Return(), Return()};
     Func("foo", {}, ty.void_(), stmts);
@@ -72,8 +72,7 @@
 }
 
 TEST_F(ResolverDiagnosticControlTest, UnreachableCode_ErrorViaAttribute) {
-    auto* attr =
-        DiagnosticAttribute(ast::DiagnosticSeverity::kError, Expr("chromium_unreachable_code"));
+    auto* attr = DiagnosticAttribute(ast::DiagnosticSeverity::kError, "chromium_unreachable_code");
 
     auto stmts = utils::Vector{Return(), Return()};
     Func("foo", {}, ty.void_(), stmts, utils::Vector{attr});
@@ -84,7 +83,7 @@
 
 TEST_F(ResolverDiagnosticControlTest, UnreachableCode_WarningViaAttribute) {
     auto* attr =
-        DiagnosticAttribute(ast::DiagnosticSeverity::kWarning, Expr("chromium_unreachable_code"));
+        DiagnosticAttribute(ast::DiagnosticSeverity::kWarning, "chromium_unreachable_code");
 
     auto stmts = utils::Vector{Return(), Return()};
     Func("foo", {}, ty.void_(), stmts, utils::Vector{attr});
@@ -94,8 +93,7 @@
 }
 
 TEST_F(ResolverDiagnosticControlTest, UnreachableCode_InfoViaAttribute) {
-    auto* attr =
-        DiagnosticAttribute(ast::DiagnosticSeverity::kInfo, Expr("chromium_unreachable_code"));
+    auto* attr = DiagnosticAttribute(ast::DiagnosticSeverity::kInfo, "chromium_unreachable_code");
 
     auto stmts = utils::Vector{Return(), Return()};
     Func("foo", {}, ty.void_(), stmts, utils::Vector{attr});
@@ -105,8 +103,7 @@
 }
 
 TEST_F(ResolverDiagnosticControlTest, UnreachableCode_OffViaAttribute) {
-    auto* attr =
-        DiagnosticAttribute(ast::DiagnosticSeverity::kOff, Expr("chromium_unreachable_code"));
+    auto* attr = DiagnosticAttribute(ast::DiagnosticSeverity::kOff, "chromium_unreachable_code");
 
     auto stmts = utils::Vector{Return(), Return()};
     Func("foo", {}, ty.void_(), stmts, utils::Vector{attr});
@@ -122,9 +119,9 @@
     //   return;
     //   return; // Should produce a warning
     // }
-    DiagnosticDirective(ast::DiagnosticSeverity::kError, Expr("chromium_unreachable_code"));
+    DiagnosticDirective(ast::DiagnosticSeverity::kError, "chromium_unreachable_code");
     auto* attr =
-        DiagnosticAttribute(ast::DiagnosticSeverity::kWarning, Expr("chromium_unreachable_code"));
+        DiagnosticAttribute(ast::DiagnosticSeverity::kWarning, "chromium_unreachable_code");
 
     auto stmts = utils::Vector{Return(), Return()};
     Func("foo", {}, ty.void_(), stmts, utils::Vector{attr});
@@ -150,7 +147,7 @@
     // }
     {
         auto* attr =
-            DiagnosticAttribute(ast::DiagnosticSeverity::kOff, Expr("chromium_unreachable_code"));
+            DiagnosticAttribute(ast::DiagnosticSeverity::kOff, "chromium_unreachable_code");
         Func("foo", {}, ty.void_(),
              utils::Vector{
                  Return(),
@@ -167,7 +164,7 @@
     }
     {
         auto* attr =
-            DiagnosticAttribute(ast::DiagnosticSeverity::kInfo, Expr("chromium_unreachable_code"));
+            DiagnosticAttribute(ast::DiagnosticSeverity::kInfo, "chromium_unreachable_code");
         Func("zoo", {}, ty.void_(),
              utils::Vector{
                  Return(),
@@ -203,7 +200,7 @@
     // }
 
     auto attr = [&](auto severity) {
-        return utils::Vector{DiagnosticAttribute(severity, Expr("chromium_unreachable_code"))};
+        return utils::Vector{DiagnosticAttribute(severity, "chromium_unreachable_code")};
     };
     Func("foo", {}, ty.void_(),
          utils::Vector{
@@ -243,7 +240,7 @@
 
 TEST_F(ResolverDiagnosticControlTest, UnrecognizedRuleName_Directive) {
     DiagnosticDirective(ast::DiagnosticSeverity::kError,
-                        Expr(Source{{12, 34}}, "chromium_unreachable_cod"));
+                        Ident(Source{{12, 34}}, "chromium_unreachable_cod"));
     EXPECT_TRUE(r()->Resolve()) << r()->error();
     EXPECT_EQ(r()->error(),
               R"(12:34 warning: unrecognized diagnostic rule 'chromium_unreachable_cod'
@@ -253,7 +250,7 @@
 
 TEST_F(ResolverDiagnosticControlTest, UnrecognizedRuleName_Attribute) {
     auto* attr = DiagnosticAttribute(ast::DiagnosticSeverity::kError,
-                                     Expr(Source{{12, 34}}, "chromium_unreachable_cod"));
+                                     Ident(Source{{12, 34}}, "chromium_unreachable_cod"));
     Func("foo", {}, ty.void_(), {}, utils::Vector{attr});
     EXPECT_TRUE(r()->Resolve()) << r()->error();
     EXPECT_EQ(r()->error(),
@@ -264,17 +261,17 @@
 
 TEST_F(ResolverDiagnosticControlTest, Conflict_SameNameSameSeverity_Directive) {
     DiagnosticDirective(ast::DiagnosticSeverity::kError,
-                        Expr(Source{{12, 34}}, "chromium_unreachable_code"));
+                        Ident(Source{{12, 34}}, "chromium_unreachable_code"));
     DiagnosticDirective(ast::DiagnosticSeverity::kError,
-                        Expr(Source{{56, 78}}, "chromium_unreachable_code"));
+                        Ident(Source{{56, 78}}, "chromium_unreachable_code"));
     EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverDiagnosticControlTest, Conflict_SameNameDifferentSeverity_Directive) {
     DiagnosticDirective(Source{{12, 34}}, ast::DiagnosticSeverity::kError,
-                        Expr("chromium_unreachable_code"));
+                        "chromium_unreachable_code");
     DiagnosticDirective(Source{{56, 78}}, ast::DiagnosticSeverity::kOff,
-                        Expr("chromium_unreachable_code"));
+                        "chromium_unreachable_code");
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
               R"(56:78 error: conflicting diagnostic directive
@@ -283,9 +280,9 @@
 
 TEST_F(ResolverDiagnosticControlTest, Conflict_SameUnknownNameDifferentSeverity_Directive) {
     DiagnosticDirective(Source{{12, 34}}, ast::DiagnosticSeverity::kError,
-                        Expr("chromium_unreachable_codes"));
+                        "chromium_unreachable_codes");
     DiagnosticDirective(Source{{56, 78}}, ast::DiagnosticSeverity::kOff,
-                        Expr("chromium_unreachable_codes"));
+                        "chromium_unreachable_codes");
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
               R"(warning: unrecognized diagnostic rule 'chromium_unreachable_codes'
@@ -300,26 +297,26 @@
 
 TEST_F(ResolverDiagnosticControlTest, Conflict_DifferentUnknownNameDifferentSeverity_Directive) {
     DiagnosticDirective(Source{{12, 34}}, ast::DiagnosticSeverity::kError,
-                        Expr("chromium_unreachable_codes"));
+                        "chromium_unreachable_codes");
     DiagnosticDirective(Source{{56, 78}}, ast::DiagnosticSeverity::kOff,
-                        Expr("chromium_unreachable_codex"));
+                        "chromium_unreachable_codex");
     EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverDiagnosticControlTest, Conflict_SameNameSameSeverity_Attribute) {
     auto* attr1 = DiagnosticAttribute(ast::DiagnosticSeverity::kError,
-                                      Expr(Source{{12, 34}}, "chromium_unreachable_code"));
+                                      Ident(Source{{12, 34}}, "chromium_unreachable_code"));
     auto* attr2 = DiagnosticAttribute(ast::DiagnosticSeverity::kError,
-                                      Expr(Source{{56, 78}}, "chromium_unreachable_code"));
+                                      Ident(Source{{56, 78}}, "chromium_unreachable_code"));
     Func("foo", {}, ty.void_(), {}, utils::Vector{attr1, attr2});
     EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverDiagnosticControlTest, Conflict_SameNameDifferentSeverity_Attribute) {
     auto* attr1 = DiagnosticAttribute(Source{{12, 34}}, ast::DiagnosticSeverity::kError,
-                                      Expr("chromium_unreachable_code"));
+                                      "chromium_unreachable_code");
     auto* attr2 = DiagnosticAttribute(Source{{56, 78}}, ast::DiagnosticSeverity::kOff,
-                                      Expr("chromium_unreachable_code"));
+                                      "chromium_unreachable_code");
     Func("foo", {}, ty.void_(), {}, utils::Vector{attr1, attr2});
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
@@ -329,9 +326,9 @@
 
 TEST_F(ResolverDiagnosticControlTest, Conflict_SameUnknownNameDifferentSeverity_Attribute) {
     auto* attr1 = DiagnosticAttribute(Source{{12, 34}}, ast::DiagnosticSeverity::kError,
-                                      Expr("chromium_unreachable_codes"));
+                                      "chromium_unreachable_codes");
     auto* attr2 = DiagnosticAttribute(Source{{56, 78}}, ast::DiagnosticSeverity::kOff,
-                                      Expr("chromium_unreachable_codes"));
+                                      "chromium_unreachable_codes");
     Func("foo", {}, ty.void_(), {}, utils::Vector{attr1, attr2});
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
@@ -347,9 +344,9 @@
 
 TEST_F(ResolverDiagnosticControlTest, Conflict_DifferentUnknownNameDifferentSeverity_Attribute) {
     auto* attr1 = DiagnosticAttribute(Source{{12, 34}}, ast::DiagnosticSeverity::kError,
-                                      Expr("chromium_unreachable_codes"));
+                                      "chromium_unreachable_codes");
     auto* attr2 = DiagnosticAttribute(Source{{56, 78}}, ast::DiagnosticSeverity::kOff,
-                                      Expr("chromium_unreachable_codex"));
+                                      "chromium_unreachable_codex");
     Func("foo", {}, ty.void_(), {}, utils::Vector{attr1, attr2});
     EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
diff --git a/src/tint/resolver/resolver.cc b/src/tint/resolver/resolver.cc
index 75bcdbd..cc6bc12 100644
--- a/src/tint/resolver/resolver.cc
+++ b/src/tint/resolver/resolver.cc
@@ -3060,9 +3060,8 @@
 
 bool Resolver::DiagnosticControl(const ast::DiagnosticControl* control) {
     Mark(control->rule_name);
-    Mark(control->rule_name->identifier);
 
-    auto rule_name = builder_->Symbols().NameFor(control->rule_name->identifier->symbol);
+    auto rule_name = builder_->Symbols().NameFor(control->rule_name->symbol);
     auto rule = ast::ParseDiagnosticRule(rule_name);
     if (rule != ast::DiagnosticRule::kUndefined) {
         validator_.DiagnosticFilters().Set(rule, control->severity);
diff --git a/src/tint/resolver/validator.cc b/src/tint/resolver/validator.cc
index eeeab83..bba2f37 100644
--- a/src/tint/resolver/validator.cc
+++ b/src/tint/resolver/validator.cc
@@ -2452,7 +2452,7 @@
     // They conflict if the rule name is the same and the severity is different.
     utils::Hashmap<Symbol, const ast::DiagnosticControl*, 8> diagnostics;
     for (auto* dc : controls) {
-        auto diag_added = diagnostics.Add(dc->rule_name->identifier->symbol, dc);
+        auto diag_added = diagnostics.Add(dc->rule_name->symbol, dc);
         if (!diag_added && (*diag_added.value)->severity != dc->severity) {
             {
                 std::ostringstream ss;
@@ -2461,8 +2461,8 @@
             }
             {
                 std::ostringstream ss;
-                ss << "severity of '" << symbols_.NameFor(dc->rule_name->identifier->symbol)
-                   << "' set to '" << dc->severity << "' here";
+                ss << "severity of '" << symbols_.NameFor(dc->rule_name->symbol) << "' set to '"
+                   << dc->severity << "' here";
                 AddNote(ss.str(), (*diag_added.value)->source);
             }
             return false;
diff --git a/src/tint/sem/diagnostic_severity_test.cc b/src/tint/sem/diagnostic_severity_test.cc
index cbb37b6..f91277b 100644
--- a/src/tint/sem/diagnostic_severity_test.cc
+++ b/src/tint/sem/diagnostic_severity_test.cc
@@ -49,13 +49,13 @@
         auto block_severity = ast::DiagnosticSeverity::kInfo;
         auto if_severity = ast::DiagnosticSeverity::kInfo;
         auto attr = [&](auto severity) {
-            return utils::Vector{DiagnosticAttribute(severity, Expr("chromium_unreachable_code"))};
+            return utils::Vector{DiagnosticAttribute(severity, "chromium_unreachable_code")};
         };
 
         auto* return_1 = Return();
         auto* if_1 = If(Expr(true), Block(utils::Vector{return_1}, attr(if_severity)));
         auto* block_1 = Block(utils::Vector{if_1}, attr(block_severity));
-        auto* func_attr = DiagnosticAttribute(func_severity, Expr("chromium_unreachable_code"));
+        auto* func_attr = DiagnosticAttribute(func_severity, "chromium_unreachable_code");
         auto* foo = Func("foo", {}, ty.void_(), utils::Vector{block_1}, utils::Vector{func_attr});
 
         auto* return_2 = Return();
@@ -74,7 +74,7 @@
 };
 
 TEST_F(DiagnosticSeverityTest, WithDirective) {
-    DiagnosticDirective(ast::DiagnosticSeverity::kError, Expr("chromium_unreachable_code"));
+    DiagnosticDirective(ast::DiagnosticSeverity::kError, "chromium_unreachable_code");
     Run(ast::DiagnosticSeverity::kError);
 }
 
diff --git a/src/tint/transform/renamer.cc b/src/tint/transform/renamer.cc
index d14b515..253ccbc 100644
--- a/src/tint/transform/renamer.cc
+++ b/src/tint/transform/renamer.cc
@@ -1314,7 +1314,7 @@
                 }
             },
             [&](const ast::DiagnosticControl* diagnostic) {
-                preserved_identifiers.Add(diagnostic->rule_name->identifier);
+                preserved_identifiers.Add(diagnostic->rule_name);
             },
             [&](const ast::TypeName* type_name) {
                 if (is_type_short_name(type_name->name)) {
diff --git a/src/tint/writer/wgsl/generator_impl.cc b/src/tint/writer/wgsl/generator_impl.cc
index 71d794f..4e32b2e 100644
--- a/src/tint/writer/wgsl/generator_impl.cc
+++ b/src/tint/writer/wgsl/generator_impl.cc
@@ -110,7 +110,7 @@
 bool GeneratorImpl::EmitDiagnosticControl(std::ostream& out,
                                           const ast::DiagnosticControl* diagnostic) {
     out << "diagnostic(" << diagnostic->severity << ", "
-        << program_->Symbols().NameFor(diagnostic->rule_name->identifier->symbol) << ")";
+        << program_->Symbols().NameFor(diagnostic->rule_name->symbol) << ")";
     return true;
 }
 
diff --git a/src/tint/writer/wgsl/generator_impl_diagnostic_test.cc b/src/tint/writer/wgsl/generator_impl_diagnostic_test.cc
index d9ce01c..b996312 100644
--- a/src/tint/writer/wgsl/generator_impl_diagnostic_test.cc
+++ b/src/tint/writer/wgsl/generator_impl_diagnostic_test.cc
@@ -20,7 +20,7 @@
 using WgslGeneratorImplTest = TestHelper;
 
 TEST_F(WgslGeneratorImplTest, Emit_DiagnosticDirective) {
-    DiagnosticDirective(ast::DiagnosticSeverity::kError, Expr("chromium_unreachable_code"));
+    DiagnosticDirective(ast::DiagnosticSeverity::kError, "chromium_unreachable_code");
 
     GeneratorImpl& gen = Build();
 
@@ -31,8 +31,7 @@
 }
 
 TEST_F(WgslGeneratorImplTest, Emit_DiagnosticAttribute) {
-    auto* attr =
-        DiagnosticAttribute(ast::DiagnosticSeverity::kError, Expr("chromium_unreachable_code"));
+    auto* attr = DiagnosticAttribute(ast::DiagnosticSeverity::kError, "chromium_unreachable_code");
     Func("foo", {}, ty.void_(), {}, utils::Vector{attr});
 
     GeneratorImpl& gen = Build();