Просмотр исходного кода

Add a macro for introducer tokens. (#4031)

Playing with the macro suggestion on #4028, replace DeclKind with some
templating that asserts the in-use token is an introducer token. This
allows type-safe usage of Lex::TokenKind, reducing the benefit of a
separate enum while improving stdout (since now this will ostream as the
keyword name).
Jon Ross-Perkins 1 год назад
Родитель
Сommit
d1862e829b

+ 1 - 0
toolchain/check/BUILD

@@ -90,6 +90,7 @@ cc_library(
         "//toolchain/base:kind_switch",
         "//toolchain/check:scope_stack",
         "//toolchain/diagnostics:diagnostic_emitter",
+        "//toolchain/lex:token_kind",
         "//toolchain/lex:tokenized_buffer",
         "//toolchain/parse:node_kind",
         "//toolchain/parse:tree",

+ 31 - 30
toolchain/check/decl_introducer_state.h

@@ -6,6 +6,7 @@
 #define CARBON_TOOLCHAIN_CHECK_DECL_INTRODUCER_STATE_H_
 
 #include "toolchain/check/keyword_modifier_set.h"
+#include "toolchain/lex/token_kind.h"
 #include "toolchain/parse/node_ids.h"
 
 namespace Carbon::Check {
@@ -14,27 +15,6 @@ namespace Carbon::Check {
 // declaration and the keyword modifiers that apply to that declaration
 // introducer.
 struct DeclIntroducerState {
-  // The kind of declaration.
-  enum DeclKind : int8_t {
-    Adapt,
-    Alias,
-    Base,
-    Class,
-    Constraint,
-    Export,
-    Fn,
-    Impl,
-    Import,
-    Interface,
-    Let,
-    Library,
-    Namespace,
-    Package,
-    Var
-  };
-
-  explicit DeclIntroducerState(DeclKind decl_kind) : kind(decl_kind) {}
-
   auto modifier_node_id(ModifierOrder order) -> Parse::NodeId {
     return ordered_modifier_node_ids[static_cast<int8_t>(order)];
   }
@@ -43,7 +23,8 @@ struct DeclIntroducerState {
     ordered_modifier_node_ids[static_cast<int8_t>(order)] = node_id;
   }
 
-  DeclKind kind;
+  // The token kind of the introducer.
+  Lex::TokenKind kind;
 
   // Nodes of modifiers on this declaration, in expected order. `Invalid` if no
   // modifier of that kind is present.
@@ -53,26 +34,46 @@ struct DeclIntroducerState {
            Parse::NodeId::Invalid};
 
   // Invariant: contains just the modifiers represented by `saw_*_modifier`.
-  KeywordModifierSet modifier_set;
+  KeywordModifierSet modifier_set = KeywordModifierSet();
 };
 
 // Stack of `DeclIntroducerState` values, representing all the declaration
 // introducers we are currently nested within. Commonly size 0 or 1, as nested
 // introducers are rare.
 class DeclIntroducerStateStack {
+ private:
+  // Returns true for introducer tokens. Supports Push/Pop `requires`.
+  template <Lex::TokenKind::RawEnumType Kind>
+  static constexpr auto IsDeclIntroducer() -> bool {
+    switch (Kind) {
+#define CARBON_TOKEN(...)
+#define CARBON_DECL_INTRODUCER_TOKEN(Name, ...) case Lex::TokenKind::Name:
+#include "toolchain/lex/token_kind.def"
+      return true;
+      default:
+        return false;
+    }
+  }
+
  public:
-  // Begins introducing a declaration of kind `k`.
-  auto Push(DeclIntroducerState::DeclKind k) -> void { stack_.emplace_back(k); }
+  // Begins a declaration introducer `Kind`.
+  template <Lex::TokenKind::RawEnumType Kind>
+    requires(IsDeclIntroducer<Kind>())
+  auto Push() -> void {
+    stack_.push_back({.kind = Lex::TokenKind::Make(Kind)});
+  }
 
   // Gets the state of declaration at the top of the stack -- the innermost
   // declaration currently being processed.
   auto innermost() -> DeclIntroducerState& { return stack_.back(); }
 
-  // Finishes introducing a declaration of kind `k` and returns the
-  // produced state.
-  auto Pop(DeclIntroducerState::DeclKind k) -> DeclIntroducerState {
-    CARBON_CHECK(stack_.back().kind == k)
-        << "Found: " << stack_.back().kind << " expected: " << k;
+  // Finishes a declaration introducer `Kind` and returns the produced state.
+  template <Lex::TokenKind::RawEnumType Kind>
+    requires(IsDeclIntroducer<Kind>())
+  auto Pop() -> DeclIntroducerState {
+    CARBON_CHECK(stack_.back().kind == Kind)
+        << "Found: " << stack_.back().kind
+        << " expected: " << Lex::TokenKind::Make(Kind);
     return stack_.pop_back_val();
   }
 

+ 2 - 2
toolchain/check/handle_alias.cpp

@@ -14,7 +14,7 @@ namespace Carbon::Check {
 
 auto HandleAliasIntroducer(Context& context,
                            Parse::AliasIntroducerId /*node_id*/) -> bool {
-  context.decl_introducer_state_stack().Push(DeclIntroducerState::Alias);
+  context.decl_introducer_state_stack().Push<Lex::TokenKind::Alias>();
   context.decl_name_stack().PushScopeAndStartName();
   return true;
 }
@@ -31,7 +31,7 @@ auto HandleAlias(Context& context, Parse::AliasId /*node_id*/) -> bool {
       PopNameComponentWithoutParams(context, Lex::TokenKind::Alias));
 
   auto introducer =
-      context.decl_introducer_state_stack().Pop(DeclIntroducerState::Alias);
+      context.decl_introducer_state_stack().Pop<Lex::TokenKind::Alias>();
   LimitModifiersOnDecl(context, introducer, KeywordModifierSet::Access);
   if (introducer.modifier_set.HasAnyOf(KeywordModifierSet::Access)) {
     context.TODO(introducer.modifier_node_id(ModifierOrder::Access),

+ 6 - 6
toolchain/check/handle_class.cpp

@@ -36,7 +36,7 @@ auto HandleClassIntroducer(Context& context, Parse::ClassIntroducerId node_id)
   // Push the bracketing node.
   context.node_stack().Push(node_id);
   // Optional modifiers and the name follow.
-  context.decl_introducer_state_stack().Push(DeclIntroducerState::Class);
+  context.decl_introducer_state_stack().Push<Lex::TokenKind::Class>();
   context.decl_name_stack().PushScopeAndStartName();
   return true;
 }
@@ -188,7 +188,7 @@ static auto BuildClassDecl(Context& context, Parse::AnyClassDeclId node_id,
   auto [_, parent_scope_inst] =
       context.name_scopes().GetInstIfValid(name_context.parent_scope_id);
   auto introducer =
-      context.decl_introducer_state_stack().Pop(DeclIntroducerState::Class);
+      context.decl_introducer_state_stack().Pop<Lex::TokenKind::Class>();
   CheckAccessModifiersOnDecl(context, introducer, parent_scope_inst);
   LimitModifiersOnDecl(context, introducer,
                        KeywordModifierSet::Class | KeywordModifierSet::Access |
@@ -355,7 +355,7 @@ static auto DiagnoseClassSpecificDeclRepeated(Context& context,
 
 auto HandleAdaptIntroducer(Context& context,
                            Parse::AdaptIntroducerId /*node_id*/) -> bool {
-  context.decl_introducer_state_stack().Push(DeclIntroducerState::Adapt);
+  context.decl_introducer_state_stack().Push<Lex::TokenKind::Adapt>();
   return true;
 }
 
@@ -365,7 +365,7 @@ auto HandleAdaptDecl(Context& context, Parse::AdaptDeclId node_id) -> bool {
 
   // Process modifiers. `extend` is permitted, no others are allowed.
   auto introducer =
-      context.decl_introducer_state_stack().Pop(DeclIntroducerState::Adapt);
+      context.decl_introducer_state_stack().Pop<Lex::TokenKind::Adapt>();
   LimitModifiersOnDecl(context, introducer, KeywordModifierSet::Extend);
 
   auto parent_class_decl =
@@ -422,7 +422,7 @@ auto HandleAdaptDecl(Context& context, Parse::AdaptDeclId node_id) -> bool {
 
 auto HandleBaseIntroducer(Context& context, Parse::BaseIntroducerId /*node_id*/)
     -> bool {
-  context.decl_introducer_state_stack().Push(DeclIntroducerState::Base);
+  context.decl_introducer_state_stack().Push<Lex::TokenKind::Base>();
   return true;
 }
 
@@ -495,7 +495,7 @@ auto HandleBaseDecl(Context& context, Parse::BaseDeclId node_id) -> bool {
 
   // Process modifiers. `extend` is required, no others are allowed.
   auto introducer =
-      context.decl_introducer_state_stack().Pop(DeclIntroducerState::Base);
+      context.decl_introducer_state_stack().Pop<Lex::TokenKind::Base>();
   LimitModifiersOnDecl(context, introducer, KeywordModifierSet::Extend);
   if (!introducer.modifier_set.HasAnyOf(KeywordModifierSet::Extend)) {
     CARBON_DIAGNOSTIC(BaseMissingExtend, Error,

+ 2 - 2
toolchain/check/handle_export.cpp

@@ -15,7 +15,7 @@ namespace Carbon::Check {
 
 auto HandleExportIntroducer(Context& context,
                             Parse::ExportIntroducerId /*node_id*/) -> bool {
-  context.decl_introducer_state_stack().Push(DeclIntroducerState::Export);
+  context.decl_introducer_state_stack().Push<Lex::TokenKind::Export>();
   // TODO: Probably need to update DeclNameStack to restrict to only namespaces.
   context.decl_name_stack().PushScopeAndStartName();
   return true;
@@ -27,7 +27,7 @@ auto HandleExportDecl(Context& context, Parse::ExportDeclId node_id) -> bool {
   context.decl_name_stack().PopScope();
 
   auto introducer =
-      context.decl_introducer_state_stack().Pop(DeclIntroducerState::Export);
+      context.decl_introducer_state_stack().Pop<Lex::TokenKind::Export>();
   LimitModifiersOnDecl(context, introducer, KeywordModifierSet::None);
 
   if (name_context.state == DeclNameStack::NameContext::State::Error) {

+ 2 - 2
toolchain/check/handle_function.cpp

@@ -30,7 +30,7 @@ auto HandleFunctionIntroducer(Context& context,
   // Push the bracketing node.
   context.node_stack().Push(node_id);
   // Optional modifiers and the name follow.
-  context.decl_introducer_state_stack().Push(DeclIntroducerState::Fn);
+  context.decl_introducer_state_stack().Push<Lex::TokenKind::Fn>();
   context.decl_name_stack().PushScopeAndStartName();
   return true;
 }
@@ -225,7 +225,7 @@ static auto BuildFunctionDecl(Context& context,
   auto [parent_scope_inst_id, parent_scope_inst] =
       context.name_scopes().GetInstIfValid(name_context.parent_scope_id);
   auto introducer =
-      context.decl_introducer_state_stack().Pop(DeclIntroducerState::Fn);
+      context.decl_introducer_state_stack().Pop<Lex::TokenKind::Fn>();
   DiagnoseModifiers(context, introducer, is_definition, parent_scope_inst_id,
                     parent_scope_inst);
   if (introducer.modifier_set.HasAnyOf(KeywordModifierSet::Access)) {

+ 2 - 2
toolchain/check/handle_impl.cpp

@@ -24,7 +24,7 @@ auto HandleImplIntroducer(Context& context, Parse::ImplIntroducerId node_id)
   context.node_stack().Push(node_id);
 
   // Optional modifiers follow.
-  context.decl_introducer_state_stack().Push(DeclIntroducerState::Impl);
+  context.decl_introducer_state_stack().Push<Lex::TokenKind::Impl>();
 
   // An impl doesn't have a name per se, but it makes the processing more
   // consistent to imagine that it does. This also gives us a scope for implicit
@@ -193,7 +193,7 @@ static auto BuildImplDecl(Context& context, Parse::AnyImplDeclId node_id)
   // TODO: Should we somehow permit access specifiers on `impl`s?
   // TODO: Handle `final` modifier.
   auto introducer =
-      context.decl_introducer_state_stack().Pop(DeclIntroducerState::Impl);
+      context.decl_introducer_state_stack().Pop<Lex::TokenKind::Impl>();
   LimitModifiersOnDecl(context, introducer, KeywordModifierSet::ImplDecl);
 
   // Finish processing the name, which should be empty, but might have

+ 6 - 6
toolchain/check/handle_import_and_package.cpp

@@ -14,42 +14,42 @@ namespace Carbon::Check {
 
 auto HandleImportIntroducer(Context& context,
                             Parse::ImportIntroducerId /*node_id*/) -> bool {
-  context.decl_introducer_state_stack().Push(DeclIntroducerState::Import);
+  context.decl_introducer_state_stack().Push<Lex::TokenKind::Import>();
   return true;
 }
 
 auto HandleImportDecl(Context& context, Parse::ImportDeclId /*node_id*/)
     -> bool {
   auto introducer =
-      context.decl_introducer_state_stack().Pop(DeclIntroducerState::Import);
+      context.decl_introducer_state_stack().Pop<Lex::TokenKind::Import>();
   LimitModifiersOnDecl(context, introducer, KeywordModifierSet::Export);
   return true;
 }
 
 auto HandleLibraryIntroducer(Context& context,
                              Parse::LibraryIntroducerId /*node_id*/) -> bool {
-  context.decl_introducer_state_stack().Push(DeclIntroducerState::Library);
+  context.decl_introducer_state_stack().Push<Lex::TokenKind::Library>();
   return true;
 }
 
 auto HandleLibraryDecl(Context& context, Parse::LibraryDeclId /*node_id*/)
     -> bool {
   auto introducer =
-      context.decl_introducer_state_stack().Pop(DeclIntroducerState::Library);
+      context.decl_introducer_state_stack().Pop<Lex::TokenKind::Library>();
   LimitModifiersOnDecl(context, introducer, KeywordModifierSet::Impl);
   return true;
 }
 
 auto HandlePackageIntroducer(Context& context,
                              Parse::PackageIntroducerId /*node_id*/) -> bool {
-  context.decl_introducer_state_stack().Push(DeclIntroducerState::Package);
+  context.decl_introducer_state_stack().Push<Lex::TokenKind::Package>();
   return true;
 }
 
 auto HandlePackageDecl(Context& context, Parse::PackageDeclId /*node_id*/)
     -> bool {
   auto introducer =
-      context.decl_introducer_state_stack().Pop(DeclIntroducerState::Package);
+      context.decl_introducer_state_stack().Pop<Lex::TokenKind::Package>();
   LimitModifiersOnDecl(context, introducer, KeywordModifierSet::Impl);
   return true;
 }

+ 2 - 2
toolchain/check/handle_interface.cpp

@@ -20,7 +20,7 @@ auto HandleInterfaceIntroducer(Context& context,
   // Push the bracketing node.
   context.node_stack().Push(node_id);
   // Optional modifiers and the name follow.
-  context.decl_introducer_state_stack().Push(DeclIntroducerState::Interface);
+  context.decl_introducer_state_stack().Push<Lex::TokenKind::Interface>();
   context.decl_name_stack().PushScopeAndStartName();
   return true;
 }
@@ -37,7 +37,7 @@ static auto BuildInterfaceDecl(Context& context,
   auto [_, parent_scope_inst] =
       context.name_scopes().GetInstIfValid(name_context.parent_scope_id);
   auto introducer =
-      context.decl_introducer_state_stack().Pop(DeclIntroducerState::Interface);
+      context.decl_introducer_state_stack().Pop<Lex::TokenKind::Interface>();
   CheckAccessModifiersOnDecl(context, introducer, parent_scope_inst);
   LimitModifiersOnDecl(context, introducer, KeywordModifierSet::Access);
 

+ 2 - 2
toolchain/check/handle_let.cpp

@@ -15,7 +15,7 @@ namespace Carbon::Check {
 
 auto HandleLetIntroducer(Context& context, Parse::LetIntroducerId node_id)
     -> bool {
-  context.decl_introducer_state_stack().Push(DeclIntroducerState::Let);
+  context.decl_introducer_state_stack().Push<Lex::TokenKind::Let>();
   // Push a bracketing node to establish the pattern context.
   context.node_stack().Push(node_id);
   return true;
@@ -83,7 +83,7 @@ auto HandleLetDecl(Context& context, Parse::LetDeclId node_id) -> bool {
       context.name_scopes().GetInstIfValid(
           context.scope_stack().PeekNameScopeId());
   auto introducer =
-      context.decl_introducer_state_stack().Pop(DeclIntroducerState::Let);
+      context.decl_introducer_state_stack().Pop<Lex::TokenKind::Let>();
   CheckAccessModifiersOnDecl(context, introducer, parent_scope_inst);
   RequireDefaultFinalOnlyInInterfaces(context, introducer, parent_scope_inst);
   LimitModifiersOnDecl(

+ 1 - 1
toolchain/check/handle_loop_statement.cpp

@@ -77,7 +77,7 @@ auto HandleForHeaderStart(Context& context, Parse::ForHeaderStartId node_id)
 }
 
 auto HandleForIn(Context& context, Parse::ForInId node_id) -> bool {
-  context.decl_introducer_state_stack().Pop(DeclIntroducerState::Var);
+  context.decl_introducer_state_stack().Pop<Lex::TokenKind::Var>();
   return context.TODO(node_id, "HandleForIn");
 }
 

+ 2 - 2
toolchain/check/handle_namespace.cpp

@@ -15,7 +15,7 @@ namespace Carbon::Check {
 auto HandleNamespaceStart(Context& context, Parse::NamespaceStartId /*node_id*/)
     -> bool {
   // Optional modifiers and the name follow.
-  context.decl_introducer_state_stack().Push(DeclIntroducerState::Namespace);
+  context.decl_introducer_state_stack().Push<Lex::TokenKind::Namespace>();
   context.decl_name_stack().PushScopeAndStartName();
   return true;
 }
@@ -25,7 +25,7 @@ auto HandleNamespace(Context& context, Parse::NamespaceId node_id) -> bool {
       PopNameComponentWithoutParams(context, Lex::TokenKind::Namespace));
 
   auto introducer =
-      context.decl_introducer_state_stack().Pop(DeclIntroducerState::Namespace);
+      context.decl_introducer_state_stack().Pop<Lex::TokenKind::Namespace>();
   LimitModifiersOnDecl(context, introducer, KeywordModifierSet::None);
 
   auto namespace_inst = SemIR::Namespace{

+ 2 - 2
toolchain/check/handle_variable.cpp

@@ -13,7 +13,7 @@ auto HandleVariableIntroducer(Context& context,
                               Parse::VariableIntroducerId node_id) -> bool {
   // No action, just a bracketing node.
   context.node_stack().Push(node_id);
-  context.decl_introducer_state_stack().Push(DeclIntroducerState::Var);
+  context.decl_introducer_state_stack().Push<Lex::TokenKind::Var>();
   return true;
 }
 
@@ -102,7 +102,7 @@ auto HandleVariableDecl(Context& context, Parse::VariableDeclId node_id)
   auto [_, parent_scope_inst] = context.name_scopes().GetInstIfValid(
       context.scope_stack().PeekNameScopeId());
   auto introducer =
-      context.decl_introducer_state_stack().Pop(DeclIntroducerState::Var);
+      context.decl_introducer_state_stack().Pop<Lex::TokenKind::Var>();
   CheckAccessModifiersOnDecl(context, introducer, parent_scope_inst);
   LimitModifiersOnDecl(context, introducer, KeywordModifierSet::Access);
   if (introducer.modifier_set.HasAnyOf(KeywordModifierSet::Access)) {

+ 1 - 39
toolchain/check/modifiers.cpp

@@ -8,43 +8,6 @@
 
 namespace Carbon::Check {
 
-// Returns the TokenKind for a DeclKind.
-static auto DeclKindToken(DeclIntroducerState::DeclKind decl_kind)
-    -> Lex::TokenKind {
-  switch (decl_kind) {
-    case DeclIntroducerState::Adapt:
-      return Lex::TokenKind::Adapt;
-    case DeclIntroducerState::Alias:
-      return Lex::TokenKind::Alias;
-    case DeclIntroducerState::Base:
-      return Lex::TokenKind::Base;
-    case DeclIntroducerState::Class:
-      return Lex::TokenKind::Class;
-    case DeclIntroducerState::Constraint:
-      return Lex::TokenKind::Constraint;
-    case DeclIntroducerState::Export:
-      return Lex::TokenKind::Export;
-    case DeclIntroducerState::Fn:
-      return Lex::TokenKind::Fn;
-    case DeclIntroducerState::Import:
-      return Lex::TokenKind::Import;
-    case DeclIntroducerState::Impl:
-      return Lex::TokenKind::Impl;
-    case DeclIntroducerState::Interface:
-      return Lex::TokenKind::Interface;
-    case DeclIntroducerState::Let:
-      return Lex::TokenKind::Let;
-    case DeclIntroducerState::Library:
-      return Lex::TokenKind::Library;
-    case DeclIntroducerState::Namespace:
-      return Lex::TokenKind::Namespace;
-    case DeclIntroducerState::Package:
-      return Lex::TokenKind::Package;
-    case DeclIntroducerState::Var:
-      return Lex::TokenKind::Var;
-  }
-}
-
 static auto DiagnoseNotAllowed(Context& context, Parse::NodeId modifier_node,
                                Lex::TokenKind decl_kind,
                                llvm::StringRef context_string,
@@ -89,8 +52,7 @@ auto ForbidModifiersOnDecl(Context& context, DeclIntroducerState& introducer,
     auto order = static_cast<ModifierOrder>(order_index);
     if (not_allowed.HasAnyOf(ModifierOrderAsSet(order))) {
       DiagnoseNotAllowed(context, introducer.modifier_node_id(order),
-                         DeclKindToken(introducer.kind), context_string,
-                         context_loc_id);
+                         introducer.kind, context_string, context_loc_id);
       introducer.set_modifier_node_id(order, Parse::NodeId::Invalid);
     }
   }

+ 27 - 15
toolchain/lex/token_kind.def

@@ -21,6 +21,8 @@
 //   - CARBON_KEYWORD_TOKEN(Name, Spelling)
 //     Defines a keyword which has the provided spelling, such as `if`.
 //     Spellings must be unique.
+//     - CARBON_DECL_INTRODUCER_TOKEN(Name, Spelling)
+//       A declaration introducer keyword, such as `fn`.
 //   - CARBON_TOKEN_WITH_VIRTUAL_NODE(TokenIndex)
 //     Wrapped around one of the above _TOKEN macros, indicates that this
 //     token has one additional virtual node in the parse tree.
@@ -137,53 +139,62 @@ CARBON_CLOSING_GROUP_SYMBOL_TOKEN(CloseSquareBracket, "]", OpenSquareBracket)
 #ifndef CARBON_KEYWORD_TOKEN
 #define CARBON_KEYWORD_TOKEN(Name, Spelling) CARBON_TOKEN(Name)
 #endif
+
+#ifndef CARBON_DECL_INTRODUCER_TOKEN
+#define CARBON_DECL_INTRODUCER_TOKEN(Name, Spelling) \
+  CARBON_KEYWORD_TOKEN(Name, Spelling)
+#endif
+
 // clang-format off
+
+CARBON_DECL_INTRODUCER_TOKEN(Adapt,       "adapt")
+CARBON_DECL_INTRODUCER_TOKEN(Alias,       "alias")
+CARBON_DECL_INTRODUCER_TOKEN(Base,        "base")
+CARBON_DECL_INTRODUCER_TOKEN(Class,       "class")
+CARBON_DECL_INTRODUCER_TOKEN(Constraint,  "constraint")
+CARBON_DECL_INTRODUCER_TOKEN(Export,      "export")
+CARBON_DECL_INTRODUCER_TOKEN(Fn,          "fn")
+CARBON_DECL_INTRODUCER_TOKEN(Impl,        "impl")
+CARBON_DECL_INTRODUCER_TOKEN(Import,      "import")
+CARBON_DECL_INTRODUCER_TOKEN(Interface,   "interface")
+CARBON_DECL_INTRODUCER_TOKEN(Let,         "let")
+CARBON_DECL_INTRODUCER_TOKEN(Library,     "library")
+CARBON_DECL_INTRODUCER_TOKEN(Namespace,   "namespace")
+CARBON_DECL_INTRODUCER_TOKEN(Package,     "package")
+CARBON_DECL_INTRODUCER_TOKEN(Var,         "var")
+
 CARBON_KEYWORD_TOKEN(Abstract,            "abstract")
-CARBON_KEYWORD_TOKEN(Adapt,               "adapt")
 CARBON_KEYWORD_TOKEN(Addr,                "addr")
-CARBON_KEYWORD_TOKEN(Alias,               "alias")
 CARBON_TOKEN_WITH_VIRTUAL_NODE(
   CARBON_KEYWORD_TOKEN(And,               "and"))
 CARBON_KEYWORD_TOKEN(Api,                 "api")
 CARBON_KEYWORD_TOKEN(As,                  "as")
 CARBON_KEYWORD_TOKEN(Auto,                "auto")
-CARBON_KEYWORD_TOKEN(Base,                "base")
 CARBON_KEYWORD_TOKEN(Bool,                "bool")
 CARBON_KEYWORD_TOKEN(Break,               "break")
 CARBON_KEYWORD_TOKEN(Case,                "case")
 CARBON_KEYWORD_TOKEN(Choice,              "choice")
-CARBON_KEYWORD_TOKEN(Class,               "class")
 CARBON_KEYWORD_TOKEN(Const,               "const")
-CARBON_KEYWORD_TOKEN(Constraint,          "constraint")
 CARBON_KEYWORD_TOKEN(Continue,            "continue")
 CARBON_KEYWORD_TOKEN(Default,             "default")
 CARBON_KEYWORD_TOKEN(Destructor,          "destructor")
 CARBON_KEYWORD_TOKEN(Else,                "else")
-CARBON_KEYWORD_TOKEN(Export,              "export")
 CARBON_KEYWORD_TOKEN(Extend,              "extend")
 CARBON_KEYWORD_TOKEN(Extern,              "extern")
 CARBON_KEYWORD_TOKEN(False,               "false")
 CARBON_KEYWORD_TOKEN(Final,               "final")
-CARBON_KEYWORD_TOKEN(Fn,                  "fn")
 CARBON_KEYWORD_TOKEN(For,                 "for")
 CARBON_KEYWORD_TOKEN(Forall,              "forall")
 CARBON_KEYWORD_TOKEN(Friend,              "friend")
 CARBON_KEYWORD_TOKEN(If,                  "if")
-CARBON_KEYWORD_TOKEN(Impl,                "impl")
 CARBON_KEYWORD_TOKEN(Impls,               "impls")
-CARBON_KEYWORD_TOKEN(Import,              "import")
 CARBON_KEYWORD_TOKEN(In,                  "in")
-CARBON_KEYWORD_TOKEN(Interface,           "interface")
-CARBON_KEYWORD_TOKEN(Let,                 "let")
-CARBON_KEYWORD_TOKEN(Library,             "library")
 CARBON_KEYWORD_TOKEN(Like,                "like")
 CARBON_KEYWORD_TOKEN(Match,               "match")
-CARBON_KEYWORD_TOKEN(Namespace,           "namespace")
 CARBON_KEYWORD_TOKEN(Not,                 "not")
 CARBON_KEYWORD_TOKEN(Observe,             "observe")
 CARBON_TOKEN_WITH_VIRTUAL_NODE(
   CARBON_KEYWORD_TOKEN(Or,                "or"))
-CARBON_KEYWORD_TOKEN(Package,             "package")
 CARBON_KEYWORD_TOKEN(Partial,             "partial")
 CARBON_KEYWORD_TOKEN(Private,             "private")
 CARBON_KEYWORD_TOKEN(Protected,           "protected")
@@ -200,11 +211,12 @@ CARBON_KEYWORD_TOKEN(True,                "true")
 CARBON_KEYWORD_TOKEN(Type,                "type")
 // Underscore is tokenized as a keyword because it's part of identifiers.
 CARBON_KEYWORD_TOKEN(Underscore,          "_")
-CARBON_KEYWORD_TOKEN(Var,                 "var")
 CARBON_KEYWORD_TOKEN(Virtual,             "virtual")
 CARBON_KEYWORD_TOKEN(Where,               "where")
 CARBON_KEYWORD_TOKEN(While,               "while")
+
 // clang-format on
+#undef CARBON_DECL_INTRODUCER_TOKEN
 #undef CARBON_KEYWORD_TOKEN
 
 CARBON_TOKEN(Identifier)

+ 3 - 0
toolchain/lex/token_kind.h

@@ -30,6 +30,9 @@ class TokenKind : public CARBON_ENUM_BASE(TokenKind) {
 
   using EnumBase::EnumBase;
 
+  // Permit creation from RawEnumType for templates.
+  using EnumBase::Make;
+
   // Permit conversion to integer for use as an array index.
   using EnumBase::AsInt;