id_kind.h 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. // Part of the Carbon Language project, under the Apache License v2.0 with LLVM
  2. // Exceptions. See /LICENSE for license information.
  3. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  4. #ifndef CARBON_TOOLCHAIN_SEM_IR_ID_KIND_H_
  5. #define CARBON_TOOLCHAIN_SEM_IR_ID_KIND_H_
  6. #include <algorithm>
  7. #include "toolchain/base/int.h"
  8. #include "toolchain/sem_ir/ids.h"
  9. namespace Carbon::SemIR {
  10. // An enum whose values are the specified types.
  11. template <typename... Types>
  12. class TypeEnum {
  13. public:
  14. static constexpr std::size_t NumTypes = sizeof...(Types);
  15. static constexpr std::size_t NumValues = NumTypes + 2;
  16. static_assert(NumValues <= 256, "Too many types for raw enum.");
  17. // TODO: Works around a clang-format bug:
  18. // https://github.com/llvm/llvm-project/issues/85476
  19. #define CARBON_OPEN_ENUM [[clang::enum_extensibility(open)]]
  20. // The underlying raw enumeration type.
  21. //
  22. // The enum_extensibility attribute indicates that this enum is intended to
  23. // take values that do not correspond to its declared enumerators.
  24. enum class CARBON_OPEN_ENUM RawEnumType : uint8_t {
  25. // The first sizeof...(Types) values correspond to the types.
  26. // An explicitly invalid value.
  27. Invalid = NumTypes,
  28. // Indicates that no type should be used.
  29. // TODO: This doesn't really fit the model of this type, but it's convenient
  30. // for all of its users.
  31. None,
  32. };
  33. #undef CARBON_OPEN_ENUM
  34. // Accesses the type given an enum value.
  35. template <RawEnumType K>
  36. requires(K != RawEnumType::Invalid)
  37. using TypeFor = __type_pack_element<static_cast<size_t>(K), Types...>;
  38. // Workaround for Clang bug https://github.com/llvm/llvm-project/issues/85461
  39. template <RawEnumType Value>
  40. static constexpr auto FromRaw = TypeEnum(Value);
  41. // Names for the `Invalid` and `None` enumeration values.
  42. static constexpr const TypeEnum& Invalid = FromRaw<RawEnumType::Invalid>;
  43. static constexpr const TypeEnum& None = FromRaw<RawEnumType::None>;
  44. // Accesses the enumeration value for the type `IdT`. If `AllowInvalid` is
  45. // set, any unexpected type is mapped to `Invalid`, otherwise an invalid type
  46. // results in a compile error.
  47. //
  48. // The `Self` parameter is an implementation detail to allow `ForImpl` to be
  49. // defined after this template, and should not be specified.
  50. template <typename IdT, bool AllowInvalid = false, typename Self = TypeEnum>
  51. static constexpr auto For = Self::template ForImpl<IdT, AllowInvalid>();
  52. // This bool indicates whether the specified type corresponds to a value in
  53. // this enum.
  54. template <typename IdT>
  55. static constexpr bool Contains = For<IdT, true>.is_valid();
  56. // Explicitly convert from the raw enum type.
  57. explicit constexpr TypeEnum(RawEnumType value) : value_(value) {}
  58. // Implicitly convert to the raw enum type, for use in `switch`.
  59. //
  60. // NOLINTNEXTLINE(google-explicit-constructor)
  61. constexpr operator RawEnumType() const { return value_; }
  62. // Conversion to bool is deleted to prevent direct use in an `if` condition
  63. // instead of comparing with another value.
  64. explicit operator bool() const = delete;
  65. // Returns the raw enum value.
  66. constexpr auto ToRaw() const -> RawEnumType { return value_; }
  67. // Returns a value that can be used as an array index. Returned value will be
  68. // < NumValues.
  69. constexpr auto ToIndex() const -> std::size_t {
  70. return static_cast<std::size_t>(value_);
  71. }
  72. // Returns whether this is a valid value, not `Invalid`.
  73. constexpr auto is_valid() const -> bool {
  74. return value_ != RawEnumType::Invalid;
  75. }
  76. private:
  77. // Translates a type to its enum value, or `Invalid`.
  78. template <typename IdT, bool AllowInvalid>
  79. static constexpr auto ForImpl() -> TypeEnum {
  80. // A bool for each type saying whether it matches. The result is the index
  81. // of the first `true` in this list. If none matches, then the result is the
  82. // length of the list, which is mapped to `Invalid`.
  83. constexpr bool TypeMatches[] = {std::same_as<IdT, Types>...};
  84. constexpr int Index =
  85. std::find(TypeMatches, TypeMatches + NumTypes, true) - TypeMatches;
  86. static_assert(Index != NumTypes || AllowInvalid,
  87. "Unexpected type passed to TypeEnum::For<...>");
  88. return TypeEnum(static_cast<RawEnumType>(Index));
  89. }
  90. RawEnumType value_;
  91. };
  92. // An enum of all the ID types used as instruction operands.
  93. using IdKind = TypeEnum<
  94. // From sem_ir/builtin_inst_kind.h.
  95. BuiltinInstKind,
  96. // From base/value_store.h.
  97. IntId, RealId, FloatId, StringLiteralValueId,
  98. // From sem_ir/id.h.
  99. InstId, AbsoluteInstId, ConstantId, EntityNameId, CompileTimeBindIndex,
  100. RuntimeParamIndex, FacetTypeId, FunctionId, ClassId, InterfaceId, ImplId,
  101. GenericId, SpecificId, ImportIRId, ImportIRInstId, LocId, BoolValue,
  102. IntKind, NameId, NameScopeId, InstBlockId, StructTypeFieldsId, TypeId,
  103. TypeBlockId, ElementIndex, LibraryNameId, FloatKind>;
  104. } // namespace Carbon::SemIR
  105. #endif // CARBON_TOOLCHAIN_SEM_IR_ID_KIND_H_