Преглед изворни кода

Move None to IdBase (#5030)

Use CRTP to eliminate per-type declarations of `None`. Note this adds
`None` to a few that may not need it, but eliminates a lot off
boilerplate.

Note this leaves `GenericInstIndex::None` because it has a more complex
construction.

Also fix `InstId::InitTombstone` to be `NoneIndex - 1`
Jon Ross-Perkins пре 1 година
родитељ
комит
f0403dadab
4 измењених фајлова са 11 додато и 138 уклоњено
  1. 10 0
      toolchain/base/index_base.h
  2. 0 2
      toolchain/check/scope_index.h
  3. 0 5
      toolchain/parse/tree.h
  4. 1 131
      toolchain/sem_ir/ids.h

+ 10 - 0
toolchain/base/index_base.h

@@ -48,6 +48,13 @@ template <typename IdT>
 struct IdBase : public AnyIdBase, public Printable<IdT> {
 struct IdBase : public AnyIdBase, public Printable<IdT> {
   using AnyIdBase::AnyIdBase;
   using AnyIdBase::AnyIdBase;
 
 
+  // Provide a standard `None` mapping to `NoneIndex`.
+  //
+  // This uses a `&` to trigger slightly different instantiation behaviors in
+  // Clang. For context on why this is needed, see http://wg21.link/CWG2800.
+  // NOLINTNEXTLINE(readability-identifier-naming)
+  static const IdT& None;
+
   auto Print(llvm::raw_ostream& out) const -> void {
   auto Print(llvm::raw_ostream& out) const -> void {
     out << IdT::Label;
     out << IdT::Label;
     if (has_value()) {
     if (has_value()) {
@@ -63,6 +70,9 @@ struct IdBase : public AnyIdBase, public Printable<IdT> {
   }
   }
 };
 };
 
 
+template <typename IdT>
+constexpr const IdT& IdBase<IdT>::None = IdT(NoneIndex);
+
 // A lightweight handle to an item that behaves like an index.
 // A lightweight handle to an item that behaves like an index.
 //
 //
 // Unlike IdBase, classes derived from IndexBase are not completely opaque, and
 // Unlike IdBase, classes derived from IndexBase are not completely opaque, and

+ 0 - 2
toolchain/check/scope_index.h

@@ -20,13 +20,11 @@ namespace Carbon::Check {
 struct ScopeIndex : public IndexBase<ScopeIndex> {
 struct ScopeIndex : public IndexBase<ScopeIndex> {
   static constexpr llvm::StringLiteral Label = "scope";
   static constexpr llvm::StringLiteral Label = "scope";
   static const ScopeIndex Package;
   static const ScopeIndex Package;
-  static const ScopeIndex None;
 
 
   using IndexBase::IndexBase;
   using IndexBase::IndexBase;
 };
 };
 
 
 constexpr ScopeIndex ScopeIndex::Package = ScopeIndex(0);
 constexpr ScopeIndex ScopeIndex::Package = ScopeIndex(0);
-constexpr ScopeIndex ScopeIndex::None = ScopeIndex(NoneIndex);
 
 
 }  // namespace Carbon::Check
 }  // namespace Carbon::Check
 
 

+ 0 - 5
toolchain/parse/tree.h

@@ -29,14 +29,9 @@ struct DeferredDefinitionIndex : public IndexBase<DeferredDefinitionIndex> {
   static constexpr llvm::StringLiteral Label = "deferred_def";
   static constexpr llvm::StringLiteral Label = "deferred_def";
   using ValueType = DeferredDefinition;
   using ValueType = DeferredDefinition;
 
 
-  static const DeferredDefinitionIndex None;
-
   using IndexBase::IndexBase;
   using IndexBase::IndexBase;
 };
 };
 
 
-constexpr DeferredDefinitionIndex DeferredDefinitionIndex::None =
-    DeferredDefinitionIndex(NoneIndex);
-
 // A function whose definition is deferred because it is defined inline in a
 // A function whose definition is deferred because it is defined inline in a
 // class or similar scope.
 // class or similar scope.
 //
 //

+ 1 - 131
toolchain/sem_ir/ids.h

@@ -40,9 +40,6 @@ struct InstId : public IdBase<InstId> {
   static constexpr llvm::StringLiteral Label = "inst";
   static constexpr llvm::StringLiteral Label = "inst";
   using ValueType = Inst;
   using ValueType = Inst;
 
 
-  // An ID with no value.
-  static const InstId None;
-
   // Represents the result of a name lookup that is temporarily disallowed
   // Represents the result of a name lookup that is temporarily disallowed
   // because the name is currently being initialized.
   // because the name is currently being initialized.
   static const InstId InitTombstone;
   static const InstId InitTombstone;
@@ -52,8 +49,7 @@ struct InstId : public IdBase<InstId> {
   auto Print(llvm::raw_ostream& out) const -> void;
   auto Print(llvm::raw_ostream& out) const -> void;
 };
 };
 
 
-constexpr InstId InstId::None = InstId(NoneIndex);
-constexpr InstId InstId::InitTombstone = InstId(NoneIndex - 2);
+constexpr InstId InstId::InitTombstone = InstId(NoneIndex - 1);
 
 
 // An ID of an instruction that is referenced absolutely by another instruction.
 // An ID of an instruction that is referenced absolutely by another instruction.
 // This should only be used as the type of a field within a typed instruction
 // This should only be used as the type of a field within a typed instruction
@@ -113,8 +109,6 @@ struct ConstantId : public IdBase<ConstantId> {
 
 
   // An ID for an expression that is not constant.
   // An ID for an expression that is not constant.
   static const ConstantId NotConstant;
   static const ConstantId NotConstant;
-  // An ID with no value.
-  static const ConstantId None;
 
 
   // Returns the constant ID corresponding to a concrete constant, which should
   // Returns the constant ID corresponding to a concrete constant, which should
   // either be in the `constants` block in the file or should be known to be
   // either be in the `constants` block in the file or should be known to be
@@ -180,36 +174,24 @@ struct ConstantId : public IdBase<ConstantId> {
 };
 };
 
 
 constexpr ConstantId ConstantId::NotConstant = ConstantId(NotConstantIndex);
 constexpr ConstantId ConstantId::NotConstant = ConstantId(NotConstantIndex);
-constexpr ConstantId ConstantId::None = ConstantId(NoneIndex);
 
 
 // The ID of a EntityName.
 // The ID of a EntityName.
 struct EntityNameId : public IdBase<EntityNameId> {
 struct EntityNameId : public IdBase<EntityNameId> {
   static constexpr llvm::StringLiteral Label = "entity_name";
   static constexpr llvm::StringLiteral Label = "entity_name";
   using ValueType = EntityName;
   using ValueType = EntityName;
 
 
-  // An ID with no value.
-  static const EntityNameId None;
-
   using IdBase::IdBase;
   using IdBase::IdBase;
 };
 };
 
 
-constexpr EntityNameId EntityNameId::None = EntityNameId(NoneIndex);
-
 // The index of a compile-time binding. This is the de Bruijn level for the
 // The index of a compile-time binding. This is the de Bruijn level for the
 // binding -- that is, this is the number of other compile time bindings whose
 // binding -- that is, this is the number of other compile time bindings whose
 // scope encloses this binding.
 // scope encloses this binding.
 struct CompileTimeBindIndex : public IndexBase<CompileTimeBindIndex> {
 struct CompileTimeBindIndex : public IndexBase<CompileTimeBindIndex> {
   static constexpr llvm::StringLiteral Label = "comp_time_bind";
   static constexpr llvm::StringLiteral Label = "comp_time_bind";
 
 
-  // An index with no value.
-  static const CompileTimeBindIndex None;
-
   using IndexBase::IndexBase;
   using IndexBase::IndexBase;
 };
 };
 
 
-constexpr CompileTimeBindIndex CompileTimeBindIndex::None =
-    CompileTimeBindIndex(NoneIndex);
-
 // The index of a runtime parameter in a function. These are allocated
 // The index of a runtime parameter in a function. These are allocated
 // sequentially, left-to-right, to the function parameters that will have
 // sequentially, left-to-right, to the function parameters that will have
 // arguments passed to them at runtime. In a `call` instruction, a runtime
 // arguments passed to them at runtime. In a `call` instruction, a runtime
@@ -220,9 +202,6 @@ constexpr CompileTimeBindIndex CompileTimeBindIndex::None =
 struct RuntimeParamIndex : public IndexBase<RuntimeParamIndex> {
 struct RuntimeParamIndex : public IndexBase<RuntimeParamIndex> {
   static constexpr llvm::StringLiteral Label = "runtime_param";
   static constexpr llvm::StringLiteral Label = "runtime_param";
 
 
-  // An index with no value.
-  static const RuntimeParamIndex None;
-
   // An placeholder for index whose value is not yet known.
   // An placeholder for index whose value is not yet known.
   static const RuntimeParamIndex Unknown;
   static const RuntimeParamIndex Unknown;
 
 
@@ -231,9 +210,6 @@ struct RuntimeParamIndex : public IndexBase<RuntimeParamIndex> {
   auto Print(llvm::raw_ostream& out) const -> void;
   auto Print(llvm::raw_ostream& out) const -> void;
 };
 };
 
 
-constexpr RuntimeParamIndex RuntimeParamIndex::None =
-    RuntimeParamIndex(NoneIndex);
-
 constexpr RuntimeParamIndex RuntimeParamIndex::Unknown =
 constexpr RuntimeParamIndex RuntimeParamIndex::Unknown =
     RuntimeParamIndex(NoneIndex - 1);
     RuntimeParamIndex(NoneIndex - 1);
 
 
@@ -242,14 +218,9 @@ struct FunctionId : public IdBase<FunctionId> {
   static constexpr llvm::StringLiteral Label = "function";
   static constexpr llvm::StringLiteral Label = "function";
   using ValueType = Function;
   using ValueType = Function;
 
 
-  // An ID with no value.
-  static const FunctionId None;
-
   using IdBase::IdBase;
   using IdBase::IdBase;
 };
 };
 
 
-constexpr FunctionId FunctionId::None = FunctionId(NoneIndex);
-
 // The ID of an IR within the set of all IRs being evaluated in the current
 // The ID of an IR within the set of all IRs being evaluated in the current
 // check execution.
 // check execution.
 struct CheckIRId : public IdBase<CheckIRId> {
 struct CheckIRId : public IdBase<CheckIRId> {
@@ -262,109 +233,66 @@ struct ClassId : public IdBase<ClassId> {
   static constexpr llvm::StringLiteral Label = "class";
   static constexpr llvm::StringLiteral Label = "class";
   using ValueType = Class;
   using ValueType = Class;
 
 
-  // An ID with no value.
-  static const ClassId None;
-
   using IdBase::IdBase;
   using IdBase::IdBase;
 };
 };
 
 
-constexpr ClassId ClassId::None = ClassId(NoneIndex);
-
 // The ID of an interface.
 // The ID of an interface.
 struct InterfaceId : public IdBase<InterfaceId> {
 struct InterfaceId : public IdBase<InterfaceId> {
   static constexpr llvm::StringLiteral Label = "interface";
   static constexpr llvm::StringLiteral Label = "interface";
   using ValueType = Interface;
   using ValueType = Interface;
 
 
-  // An ID with no value.
-  static const InterfaceId None;
-
   using IdBase::IdBase;
   using IdBase::IdBase;
 };
 };
 
 
-constexpr InterfaceId InterfaceId::None = InterfaceId(NoneIndex);
-
 // The ID of an associated constant.
 // The ID of an associated constant.
 struct AssociatedConstantId : public IdBase<AssociatedConstantId> {
 struct AssociatedConstantId : public IdBase<AssociatedConstantId> {
   static constexpr llvm::StringLiteral Label = "assoc_const";
   static constexpr llvm::StringLiteral Label = "assoc_const";
   using ValueType = AssociatedConstant;
   using ValueType = AssociatedConstant;
 
 
-  // An ID with no value.
-  static const AssociatedConstantId None;
-
   using IdBase::IdBase;
   using IdBase::IdBase;
 };
 };
 
 
-constexpr AssociatedConstantId AssociatedConstantId::None =
-    AssociatedConstantId(NoneIndex);
-
 // The ID of an facet type value.
 // The ID of an facet type value.
 struct FacetTypeId : public IdBase<FacetTypeId> {
 struct FacetTypeId : public IdBase<FacetTypeId> {
   static constexpr llvm::StringLiteral Label = "facet_type";
   static constexpr llvm::StringLiteral Label = "facet_type";
   using ValueType = FacetTypeInfo;
   using ValueType = FacetTypeInfo;
 
 
-  // An ID with no value.
-  static const FacetTypeId None;
-
   using IdBase::IdBase;
   using IdBase::IdBase;
 };
 };
 
 
-constexpr FacetTypeId FacetTypeId::None = FacetTypeId(NoneIndex);
-
 // The ID of an resolved facet type value.
 // The ID of an resolved facet type value.
 struct CompleteFacetTypeId : public IdBase<CompleteFacetTypeId> {
 struct CompleteFacetTypeId : public IdBase<CompleteFacetTypeId> {
   static constexpr llvm::StringLiteral Label = "complete_facet_type";
   static constexpr llvm::StringLiteral Label = "complete_facet_type";
   using ValueType = CompleteFacetType;
   using ValueType = CompleteFacetType;
 
 
-  // An ID with no value.
-  static const CompleteFacetTypeId None;
-
   using IdBase::IdBase;
   using IdBase::IdBase;
 };
 };
 
 
-constexpr CompleteFacetTypeId CompleteFacetTypeId::None =
-    CompleteFacetTypeId(NoneIndex);
-
 // The ID of an impl.
 // The ID of an impl.
 struct ImplId : public IdBase<ImplId> {
 struct ImplId : public IdBase<ImplId> {
   static constexpr llvm::StringLiteral Label = "impl";
   static constexpr llvm::StringLiteral Label = "impl";
   using ValueType = Impl;
   using ValueType = Impl;
 
 
-  // An ID with no value.
-  static const ImplId None;
-
   using IdBase::IdBase;
   using IdBase::IdBase;
 };
 };
 
 
-constexpr ImplId ImplId::None = ImplId(NoneIndex);
-
 // The ID of a generic.
 // The ID of a generic.
 struct GenericId : public IdBase<GenericId> {
 struct GenericId : public IdBase<GenericId> {
   static constexpr llvm::StringLiteral Label = "generic";
   static constexpr llvm::StringLiteral Label = "generic";
   using ValueType = Generic;
   using ValueType = Generic;
 
 
-  // An ID with no value.
-  static const GenericId None;
-
   using IdBase::IdBase;
   using IdBase::IdBase;
 };
 };
 
 
-constexpr GenericId GenericId::None = GenericId(NoneIndex);
-
 // The ID of a specific, which is the result of specifying the generic arguments
 // The ID of a specific, which is the result of specifying the generic arguments
 // for a generic.
 // for a generic.
 struct SpecificId : public IdBase<SpecificId> {
 struct SpecificId : public IdBase<SpecificId> {
   static constexpr llvm::StringLiteral Label = "specific";
   static constexpr llvm::StringLiteral Label = "specific";
   using ValueType = Specific;
   using ValueType = Specific;
 
 
-  // An ID with no value. This is typically used to represent a non-generic
-  // entity.
-  static const SpecificId None;
-
   using IdBase::IdBase;
   using IdBase::IdBase;
 };
 };
 
 
-constexpr SpecificId SpecificId::None = SpecificId(NoneIndex);
-
 // The index of an instruction that depends on generic parameters within a
 // The index of an instruction that depends on generic parameters within a
 // region of a generic. A corresponding specific version of the instruction can
 // region of a generic. A corresponding specific version of the instruction can
 // be found in each specific corresponding to that generic. This is a pair of a
 // be found in each specific corresponding to that generic. This is a pair of a
@@ -419,22 +347,14 @@ struct ImportCppId : public IdBase<ImportCppId> {
   static constexpr llvm::StringLiteral Label = "import_cpp";
   static constexpr llvm::StringLiteral Label = "import_cpp";
   using ValueType = ImportCpp;
   using ValueType = ImportCpp;
 
 
-  // An ID with no value.
-  static const ImportCppId None;
-
   using IdBase::IdBase;
   using IdBase::IdBase;
 };
 };
 
 
-constexpr ImportCppId ImportCppId::None = ImportCppId(NoneIndex);
-
 // The ID of an IR within the set of imported IRs, both direct and indirect.
 // The ID of an IR within the set of imported IRs, both direct and indirect.
 struct ImportIRId : public IdBase<ImportIRId> {
 struct ImportIRId : public IdBase<ImportIRId> {
   static constexpr llvm::StringLiteral Label = "ir";
   static constexpr llvm::StringLiteral Label = "ir";
   using ValueType = ImportIR;
   using ValueType = ImportIR;
 
 
-  // An ID with no value.
-  static const ImportIRId None;
-
   // The implicit `api` import, for an `impl` file. A null entry is added if
   // The implicit `api` import, for an `impl` file. A null entry is added if
   // there is none, as in an `api`, in which case this ID should not show up in
   // there is none, as in an `api`, in which case this ID should not show up in
   // instructions.
   // instructions.
@@ -443,7 +363,6 @@ struct ImportIRId : public IdBase<ImportIRId> {
   using IdBase::IdBase;
   using IdBase::IdBase;
 };
 };
 
 
-constexpr ImportIRId ImportIRId::None = ImportIRId(NoneIndex);
 constexpr ImportIRId ImportIRId::ApiForImpl = ImportIRId(0);
 constexpr ImportIRId ImportIRId::ApiForImpl = ImportIRId(0);
 
 
 // A boolean value.
 // A boolean value.
@@ -536,9 +455,6 @@ struct NameId : public IdBase<NameId> {
   // names().GetFormatted() is used for diagnostics.
   // names().GetFormatted() is used for diagnostics.
   using DiagnosticType = DiagnosticTypeInfo<std::string>;
   using DiagnosticType = DiagnosticTypeInfo<std::string>;
 
 
-  // An ID with no value.
-  static const NameId None;
-
   // An enum of special names.
   // An enum of special names.
   enum class SpecialNameId : uint8_t {
   enum class SpecialNameId : uint8_t {
 #define CARBON_SPECIAL_NAME_ID_FOR_ENUM(Name) Name,
 #define CARBON_SPECIAL_NAME_ID_FOR_ENUM(Name) Name,
@@ -582,8 +498,6 @@ struct NameId : public IdBase<NameId> {
   auto Print(llvm::raw_ostream& out) const -> void;
   auto Print(llvm::raw_ostream& out) const -> void;
 };
 };
 
 
-constexpr NameId NameId::None = NameId(NoneIndex);
-
 // Define the special `static const NameId` values.
 // Define the special `static const NameId` values.
 #define CARBON_SPECIAL_NAME_ID_FOR_DEF(Name) \
 #define CARBON_SPECIAL_NAME_ID_FOR_DEF(Name) \
   constexpr NameId NameId::Name =            \
   constexpr NameId NameId::Name =            \
@@ -602,15 +516,12 @@ struct NameScopeId : public IdBase<NameScopeId> {
   static constexpr llvm::StringLiteral Label = "name_scope";
   static constexpr llvm::StringLiteral Label = "name_scope";
   using ValueType = NameScope;
   using ValueType = NameScope;
 
 
-  // An ID with no value.
-  static const NameScopeId None;
   // The package (or file) name scope, guaranteed to be the first added.
   // The package (or file) name scope, guaranteed to be the first added.
   static const NameScopeId Package;
   static const NameScopeId Package;
 
 
   using IdBase::IdBase;
   using IdBase::IdBase;
 };
 };
 
 
-constexpr NameScopeId NameScopeId::None = NameScopeId(NoneIndex);
 constexpr NameScopeId NameScopeId::Package = NameScopeId(0);
 constexpr NameScopeId NameScopeId::Package = NameScopeId(0);
 
 
 // The ID of an instruction block.
 // The ID of an instruction block.
@@ -637,9 +548,6 @@ struct InstBlockId : public IdBase<InstBlockId> {
   // be inserted into it.
   // be inserted into it.
   static const InstBlockId GlobalInit;
   static const InstBlockId GlobalInit;
 
 
-  // An ID with no value.
-  static const InstBlockId None;
-
   // An ID for unreachable code.
   // An ID for unreachable code.
   static const InstBlockId Unreachable;
   static const InstBlockId Unreachable;
 
 
@@ -651,7 +559,6 @@ constexpr InstBlockId InstBlockId::Empty = InstBlockId(0);
 constexpr InstBlockId InstBlockId::Exports = InstBlockId(1);
 constexpr InstBlockId InstBlockId::Exports = InstBlockId(1);
 constexpr InstBlockId InstBlockId::ImportRefs = InstBlockId(2);
 constexpr InstBlockId InstBlockId::ImportRefs = InstBlockId(2);
 constexpr InstBlockId InstBlockId::GlobalInit = InstBlockId(3);
 constexpr InstBlockId InstBlockId::GlobalInit = InstBlockId(3);
-constexpr InstBlockId InstBlockId::None = InstBlockId(NoneIndex);
 constexpr InstBlockId InstBlockId::Unreachable = InstBlockId(NoneIndex - 1);
 constexpr InstBlockId InstBlockId::Unreachable = InstBlockId(NoneIndex - 1);
 
 
 // An ID of an instruction block that is referenced absolutely by an
 // An ID of an instruction block that is referenced absolutely by an
@@ -704,14 +611,9 @@ struct ExprRegionId : public IdBase<ExprRegionId> {
   static constexpr llvm::StringLiteral Label = "region";
   static constexpr llvm::StringLiteral Label = "region";
   using ValueType = ExprRegion;
   using ValueType = ExprRegion;
 
 
-  // An ID with no value.
-  static const ExprRegionId None;
-
   using IdBase::IdBase;
   using IdBase::IdBase;
 };
 };
 
 
-constexpr ExprRegionId ExprRegionId::None = ExprRegionId(NoneIndex);
-
 // The ID of a struct type field block.
 // The ID of a struct type field block.
 struct StructTypeFieldsId : public IdBase<StructTypeFieldsId> {
 struct StructTypeFieldsId : public IdBase<StructTypeFieldsId> {
   static constexpr llvm::StringLiteral Label = "struct_type_fields";
   static constexpr llvm::StringLiteral Label = "struct_type_fields";
@@ -719,9 +621,6 @@ struct StructTypeFieldsId : public IdBase<StructTypeFieldsId> {
   using ElementType = StructTypeField;
   using ElementType = StructTypeField;
   using ValueType = llvm::MutableArrayRef<StructTypeField>;
   using ValueType = llvm::MutableArrayRef<StructTypeField>;
 
 
-  // An ID with no value.
-  static const StructTypeFieldsId None;
-
   // The canonical empty block, reused to avoid allocating empty vectors. Always
   // The canonical empty block, reused to avoid allocating empty vectors. Always
   // the 0-index block.
   // the 0-index block.
   static const StructTypeFieldsId Empty;
   static const StructTypeFieldsId Empty;
@@ -729,8 +628,6 @@ struct StructTypeFieldsId : public IdBase<StructTypeFieldsId> {
   using IdBase::IdBase;
   using IdBase::IdBase;
 };
 };
 
 
-constexpr StructTypeFieldsId StructTypeFieldsId::None =
-    StructTypeFieldsId(NoneIndex);
 constexpr StructTypeFieldsId StructTypeFieldsId::Empty = StructTypeFieldsId(0);
 constexpr StructTypeFieldsId StructTypeFieldsId::Empty = StructTypeFieldsId(0);
 
 
 // The ID of a type.
 // The ID of a type.
@@ -742,9 +639,6 @@ struct TypeId : public IdBase<TypeId> {
   // `InstIdAsType` or `TypeOfInstId` as the diagnostic argument type.
   // `InstIdAsType` or `TypeOfInstId` as the diagnostic argument type.
   using DiagnosticType = DiagnosticTypeInfo<std::string>;
   using DiagnosticType = DiagnosticTypeInfo<std::string>;
 
 
-  // An ID with no value.
-  static const TypeId None;
-
   using IdBase::IdBase;
   using IdBase::IdBase;
 
 
   // Returns the ID of the type corresponding to the constant `const_id`, which
   // Returns the ID of the type corresponding to the constant `const_id`, which
@@ -765,8 +659,6 @@ struct TypeId : public IdBase<TypeId> {
   auto Print(llvm::raw_ostream& out) const -> void;
   auto Print(llvm::raw_ostream& out) const -> void;
 };
 };
 
 
-constexpr TypeId TypeId::None = TypeId(NoneIndex);
-
 // The ID of a type block.
 // The ID of a type block.
 struct TypeBlockId : public IdBase<TypeBlockId> {
 struct TypeBlockId : public IdBase<TypeBlockId> {
   static constexpr llvm::StringLiteral Label = "type_block";
   static constexpr llvm::StringLiteral Label = "type_block";
@@ -774,9 +666,6 @@ struct TypeBlockId : public IdBase<TypeBlockId> {
   using ElementType = TypeId;
   using ElementType = TypeId;
   using ValueType = llvm::MutableArrayRef<ElementType>;
   using ValueType = llvm::MutableArrayRef<ElementType>;
 
 
-  // An ID with no value.
-  static const TypeBlockId None;
-
   // The canonical empty block, reused to avoid allocating empty vectors. Always
   // The canonical empty block, reused to avoid allocating empty vectors. Always
   // the 0-index block.
   // the 0-index block.
   static const TypeBlockId Empty;
   static const TypeBlockId Empty;
@@ -784,27 +673,19 @@ struct TypeBlockId : public IdBase<TypeBlockId> {
   using IdBase::IdBase;
   using IdBase::IdBase;
 };
 };
 
 
-constexpr TypeBlockId TypeBlockId::None = TypeBlockId(NoneIndex);
 constexpr TypeBlockId TypeBlockId::Empty = TypeBlockId(0);
 constexpr TypeBlockId TypeBlockId::Empty = TypeBlockId(0);
 
 
 // An index for element access, for structs, tuples, and classes.
 // An index for element access, for structs, tuples, and classes.
 struct ElementIndex : public IndexBase<ElementIndex> {
 struct ElementIndex : public IndexBase<ElementIndex> {
   static constexpr llvm::StringLiteral Label = "element";
   static constexpr llvm::StringLiteral Label = "element";
   using IndexBase::IndexBase;
   using IndexBase::IndexBase;
-
-  // An ID with no value.
-  static const ElementIndex None;
 };
 };
 
 
-constexpr ElementIndex ElementIndex::None = ElementIndex(NoneIndex);
-
 // The ID of a library name. This is either a string literal or `default`.
 // The ID of a library name. This is either a string literal or `default`.
 struct LibraryNameId : public IdBase<LibraryNameId> {
 struct LibraryNameId : public IdBase<LibraryNameId> {
   static constexpr llvm::StringLiteral Label = "library_name";
   static constexpr llvm::StringLiteral Label = "library_name";
   using DiagnosticType = DiagnosticTypeInfo<std::string>;
   using DiagnosticType = DiagnosticTypeInfo<std::string>;
 
 
-  // An ID with no value.
-  static const LibraryNameId None;
   // The name of `default`.
   // The name of `default`.
   static const LibraryNameId Default;
   static const LibraryNameId Default;
   // Track cases where the library name was set, but has been diagnosed and
   // Track cases where the library name was set, but has been diagnosed and
@@ -825,7 +706,6 @@ struct LibraryNameId : public IdBase<LibraryNameId> {
   auto Print(llvm::raw_ostream& out) const -> void;
   auto Print(llvm::raw_ostream& out) const -> void;
 };
 };
 
 
-constexpr LibraryNameId LibraryNameId::None = LibraryNameId(NoneIndex);
 constexpr LibraryNameId LibraryNameId::Default = LibraryNameId(NoneIndex - 1);
 constexpr LibraryNameId LibraryNameId::Default = LibraryNameId(NoneIndex - 1);
 constexpr LibraryNameId LibraryNameId::Error = LibraryNameId(NoneIndex - 2);
 constexpr LibraryNameId LibraryNameId::Error = LibraryNameId(NoneIndex - 2);
 
 
@@ -834,14 +714,9 @@ struct ImportIRInstId : public IdBase<ImportIRInstId> {
   static constexpr llvm::StringLiteral Label = "import_ir_inst";
   static constexpr llvm::StringLiteral Label = "import_ir_inst";
   using ValueType = ImportIRInst;
   using ValueType = ImportIRInst;
 
 
-  // An ID with no value.
-  static const ImportIRInstId None;
-
   using IdBase::IdBase;
   using IdBase::IdBase;
 };
 };
 
 
-constexpr ImportIRInstId ImportIRInstId::None = ImportIRInstId(NoneIndex);
-
 // A SemIR location used as the location of instructions.
 // A SemIR location used as the location of instructions.
 //
 //
 // Contents:
 // Contents:
@@ -855,9 +730,6 @@ struct LocId : public IdBase<LocId> {
   // operations performed implicitly.
   // operations performed implicitly.
   static const int32_t ImplicitBit = 1 << 30;
   static const int32_t ImplicitBit = 1 << 30;
 
 
-  // An ID with no value.
-  static const LocId None;
-
   using IdBase::IdBase;
   using IdBase::IdBase;
 
 
   // NOLINTNEXTLINE(google-explicit-constructor)
   // NOLINTNEXTLINE(google-explicit-constructor)
@@ -909,8 +781,6 @@ struct LocId : public IdBase<LocId> {
   auto Print(llvm::raw_ostream& out) const -> void;
   auto Print(llvm::raw_ostream& out) const -> void;
 };
 };
 
 
-constexpr LocId LocId::None = LocId(Parse::NodeId::None);
-
 // Polymorphic id for fields in `Any[...]` typed instruction category. Used for
 // Polymorphic id for fields in `Any[...]` typed instruction category. Used for
 // fields where the specific instruction structs have different field types in
 // fields where the specific instruction structs have different field types in
 // that position or do not have a field in that position at all. Allows
 // that position or do not have a field in that position at all. Allows