diff --git a/common/ostream.h b/common/ostream.h index 2ada59306379..d06c42da4d47 100644 --- a/common/ostream.h +++ b/common/ostream.h @@ -17,7 +17,7 @@ namespace Carbon { // CRTP base class for printable types. Children (DerivedT) must implement: -// - auto Print(llvm::raw_ostream& out) -> void +// - auto Print(llvm::raw_ostream& out) const -> void template class Printable { // Provides simple printing for debuggers. diff --git a/toolchain/check/keyword_modifier_set.h b/toolchain/check/keyword_modifier_set.h index 8800d9cc741e..de00dca33391 100644 --- a/toolchain/check/keyword_modifier_set.h +++ b/toolchain/check/keyword_modifier_set.h @@ -23,7 +23,7 @@ class KeywordModifierSet { // // We expect this to grow, so are using a bigger size than needed. // NOLINTNEXTLINE(performance-enum-size) - enum Enum : uint32_t { + enum RawEnumType : uint32_t { // At most one of these access modifiers allowed for a given declaration, // and if present it must be first: Private = 1 << 0, @@ -61,7 +61,7 @@ class KeywordModifierSet { // Support implicit conversion so that the difference with the member enum is // opaque. // NOLINTNEXTLINE(google-explicit-constructor) - constexpr KeywordModifierSet(Enum set) : set_(set) {} + constexpr KeywordModifierSet(RawEnumType set) : set_(set) {} // Adds entries to the set. auto Add(KeywordModifierSet set) -> void { set_ |= set.set_; } @@ -70,11 +70,11 @@ class KeywordModifierSet { // Returns true if there's a non-empty set intersection. constexpr auto HasAnyOf(KeywordModifierSet other) -> bool { - return !(*this & other).empty(); + return set_ & other.set_; } // Returns true if empty. - constexpr auto empty() -> bool { return set_ == Enum::None; } + constexpr auto empty() -> bool { return !set_; } // Returns the set intersection. constexpr auto operator&(KeywordModifierSet other) -> KeywordModifierSet { @@ -85,7 +85,7 @@ class KeywordModifierSet { auto operator~() -> KeywordModifierSet { return ~set_; } private: - Enum set_; + RawEnumType set_; }; static_assert(!KeywordModifierSet(KeywordModifierSet::Access) diff --git a/toolchain/check/node_stack.h b/toolchain/check/node_stack.h index bfc0082a5549..1b4470ee3b04 100644 --- a/toolchain/check/node_stack.h +++ b/toolchain/check/node_stack.h @@ -118,13 +118,13 @@ class NodeStack { // Returns whether the node on the top of the stack has an overlapping // category. auto PeekIs(Parse::NodeCategory category) const -> bool { - return !stack_.empty() && !!(PeekNodeKind().category() & category); + return !stack_.empty() && PeekNodeKind().category().HasAnyOf(category); } // Returns whether the node on the top of the stack has an overlapping // category. Templated for consistency with other functions taking a parse // node category. - template + template auto PeekIs() const -> bool { return PeekIs(RequiredParseCategory); } @@ -216,7 +216,7 @@ class NodeStack { } // Pops the top of the stack and returns the node_id and the ID. - template + template auto PopWithNodeId() -> auto { auto id = Peek(); Parse::NodeIdInCategory node_id( @@ -242,7 +242,7 @@ class NodeStack { } // Pops the top of the stack and returns the ID. - template + template auto Pop() -> auto { return PopWithNodeId().second; } @@ -265,7 +265,7 @@ class NodeStack { // Pops the top of the stack if it has the given category, and returns the ID. // Otherwise returns std::nullopt. - template + template auto PopIf() -> std::optional())> { if (PeekIs()) { return Pop(); @@ -286,7 +286,7 @@ class NodeStack { // Pops the top of the stack and returns the node_id and the ID if it is // of the specified category. - template + template auto PopWithNodeIdIf() -> std::pair, decltype(PopIf())> { @@ -314,7 +314,7 @@ class NodeStack { } // Peeks at the ID associated with the top of the name stack. - template + template auto Peek() const -> auto { Entry back = stack_.back(); RequireParseCategory(back.node_id); @@ -358,14 +358,14 @@ class NodeStack { -> std::optional { std::optional result; auto set_id_if_category_is = [&](Parse::NodeCategory cat, Id::Kind kind) { - if (!!(category & cat)) { + if (category.HasAnyOf(cat)) { // Check for no consistent Id::Kind due to category with multiple bits // set. When computing the Id::Kind for a node kind, a partial category // match is OK, so long as we don't match two inconsistent categories. // When computing the Id::Kind for a category query, the query can't // have any extra bits set or we could be popping a node that is not in // this category. - if (for_node_kind ? result.has_value() : !!(category & ~cat)) { + if (for_node_kind ? result.has_value() : category.HasAnyOf(~cat)) { result = Id::Kind::Invalid; } else { result = kind; @@ -515,10 +515,10 @@ class NodeStack { } // Require an entry to have the given Parse::NodeCategory. - template + template auto RequireParseCategory(Parse::NodeId node_id) const -> void { auto kind = parse_tree_->node_kind(node_id); - CARBON_CHECK(!!(RequiredParseCategory & kind.category())) + CARBON_CHECK(kind.category().HasAnyOf(RequiredParseCategory)) << "Expected " << RequiredParseCategory << ", found " << kind << " with category " << kind.category(); } diff --git a/toolchain/parse/BUILD b/toolchain/parse/BUILD index bd8448d170df..32d49ab8a33f 100644 --- a/toolchain/parse/BUILD +++ b/toolchain/parse/BUILD @@ -25,6 +25,7 @@ cc_library( deps = [ "//common:check", "//common:enum_base", + "//common:ostream", "//toolchain/base:index_base", "//toolchain/lex:token_kind", "@llvm-project//llvm:Support", diff --git a/toolchain/parse/extract.cpp b/toolchain/parse/extract.cpp index a8ba7e837bf3..ab519dc9e93b 100644 --- a/toolchain/parse/extract.cpp +++ b/toolchain/parse/extract.cpp @@ -96,7 +96,7 @@ static auto NodeIdInCategoryAccept(NodeCategory category, const Tree* tree, const Tree::SiblingIterator& it, Tree::SiblingIterator end, ErrorBuilder* trace) -> bool { - if (it == end || !(tree->node_kind(*it).category() & category)) { + if (it == end || !tree->node_kind(*it).category().HasAnyOf(category)) { if (trace) { *trace << "NodeIdInCategory " << category << " error: "; if (it == end) { @@ -115,7 +115,7 @@ static auto NodeIdInCategoryAccept(NodeCategory category, const Tree* tree, } // Extract a `NodeIdInCategory` as a single child. -template +template struct Extractable> { static auto Extract(const Tree* tree, Tree::SiblingIterator& it, Tree::SiblingIterator end, ErrorBuilder* trace) diff --git a/toolchain/parse/node_ids.h b/toolchain/parse/node_ids.h index 1256cfe12549..dc69358ff839 100644 --- a/toolchain/parse/node_ids.h +++ b/toolchain/parse/node_ids.h @@ -50,14 +50,14 @@ const NodeKind& NodeIdForKind::Kind = K; #include "toolchain/parse/node_kind.def" // NodeId that matches any NodeKind whose `category()` overlaps with `Category`. -template +template struct NodeIdInCategory : public NodeId { // Support conversion from `NodeIdForKind` if Kind's category // overlaps with `Category`. template // NOLINTNEXTLINE(google-explicit-constructor) NodeIdInCategory(NodeIdForKind node_id) : NodeId(node_id) { - CARBON_CHECK(!!(Kind.category() & Category)); + CARBON_CHECK(Kind.category().HasAnyOf(Category)); } constexpr explicit NodeIdInCategory(NodeId node_id) : NodeId(node_id) {} diff --git a/toolchain/parse/node_kind.cpp b/toolchain/parse/node_kind.cpp index 68798d1637a5..d49a8f0d50d7 100644 --- a/toolchain/parse/node_kind.cpp +++ b/toolchain/parse/node_kind.cpp @@ -10,16 +10,15 @@ namespace Carbon::Parse { -auto operator<<(llvm::raw_ostream& output, NodeCategory category) - -> llvm::raw_ostream& { - if (!category) { - output << ""; +auto NodeCategory::Print(llvm::raw_ostream& out) const -> void { + if (!value_) { + out << ""; } else { llvm::ListSeparator sep("|"); -#define CARBON_NODE_CATEGORY(Name) \ - if (!!(category & NodeCategory::Name)) { \ - output << sep << #Name; \ +#define CARBON_NODE_CATEGORY(Name) \ + if (value_ & NodeCategory::Name) { \ + out << sep << #Name; \ } CARBON_NODE_CATEGORY(Decl); CARBON_NODE_CATEGORY(Expr); @@ -31,7 +30,6 @@ auto operator<<(llvm::raw_ostream& output, NodeCategory category) CARBON_NODE_CATEGORY(Statement); #undef CARBON_NODE_CATEGORY } - return output; } CARBON_DEFINE_ENUM_CLASS_NAMES(NodeKind) = { diff --git a/toolchain/parse/node_kind.h b/toolchain/parse/node_kind.h index a80ed85ef27d..281713c74c50 100644 --- a/toolchain/parse/node_kind.h +++ b/toolchain/parse/node_kind.h @@ -8,6 +8,7 @@ #include #include "common/enum_base.h" +#include "common/ostream.h" #include "llvm/ADT/BitmaskEnum.h" #include "toolchain/lex/token_kind.h" @@ -16,30 +17,50 @@ namespace Carbon::Parse { LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE(); // Represents a set of keyword modifiers, using a separate bit per modifier. -// -// We expect this to grow, so are using a bigger size than needed. -// NOLINTNEXTLINE(performance-enum-size) -enum class NodeCategory : uint32_t { - Decl = 1 << 0, - Expr = 1 << 1, - ImplAs = 1 << 2, - MemberExpr = 1 << 3, - MemberName = 1 << 4, - Modifier = 1 << 5, - Pattern = 1 << 6, - Statement = 1 << 7, - None = 0, +class NodeCategory : public Printable { + public: + // Provide values as an enum. This doesn't expose these as NodeCategory + // instances just due to the duplication of declarations that would cause. + // + // We expect this to grow, so are using a bigger size than needed. + // NOLINTNEXTLINE(performance-enum-size) + enum RawEnumType : uint32_t { + Decl = 1 << 0, + Expr = 1 << 1, + ImplAs = 1 << 2, + MemberExpr = 1 << 3, + MemberName = 1 << 4, + Modifier = 1 << 5, + Pattern = 1 << 6, + Statement = 1 << 7, + None = 0, - LLVM_MARK_AS_BITMASK_ENUM(/*LargestValue=*/Statement) + LLVM_MARK_AS_BITMASK_ENUM(/*LargestValue=*/Statement) + }; + + // Support implicit conversion so that the difference with the member enum is + // opaque. + // NOLINTNEXTLINE(google-explicit-constructor) + constexpr NodeCategory(RawEnumType value) : value_(value) {} + + // Returns true if there's a non-empty set intersection. + constexpr auto HasAnyOf(NodeCategory other) -> bool { + return value_ & other.value_; + } + + // Returns the set inverse. + constexpr auto operator~() -> NodeCategory { return ~value_; } + + auto operator==(const NodeCategory& other) const -> bool { + return value_ == other.value_; + } + + auto Print(llvm::raw_ostream& out) const -> void; + + private: + RawEnumType value_; }; -constexpr auto operator!(NodeCategory k) -> bool { - return !static_cast(k); -} - -auto operator<<(llvm::raw_ostream& output, NodeCategory category) - -> llvm::raw_ostream&; - CARBON_DEFINE_RAW_ENUM_CLASS(NodeKind, uint8_t) { #define CARBON_PARSE_NODE_KIND(Name) CARBON_RAW_ENUM_ENUMERATOR(Name) #include "toolchain/parse/node_kind.def" diff --git a/toolchain/parse/tree.h b/toolchain/parse/tree.h index 6d47204e0d98..e80cf7117745 100644 --- a/toolchain/parse/tree.h +++ b/toolchain/parse/tree.h @@ -525,10 +525,10 @@ struct Tree::ConvertTo> { static auto AllowedFor(NodeKind kind) -> bool { return kind == K; } }; -template +template struct Tree::ConvertTo> { static auto AllowedFor(NodeKind kind) -> bool { - return !!(kind.category() & C); + return kind.category().HasAnyOf(C); } }; diff --git a/toolchain/parse/typed_nodes.h b/toolchain/parse/typed_nodes.h index 98ddc3972dac..319678cd0ee8 100644 --- a/toolchain/parse/typed_nodes.h +++ b/toolchain/parse/typed_nodes.h @@ -27,7 +27,8 @@ template using CommaSeparatedList = llvm::SmallVector>; // This class provides a shorthand for defining parse node kinds for leaf nodes. -template +template struct LeafNode { static constexpr auto Kind = KindT.Define({.category = Category, .child_count = 0}); @@ -314,7 +315,7 @@ struct ReturnType { }; // A function signature: `fn F() -> i32`. -template +template struct FunctionSignature { static constexpr auto Kind = KindT.Define( {.category = Category, .bracketed_by = FunctionIntroducer::Kind}); @@ -962,7 +963,7 @@ struct StructTypeLiteral { using ClassIntroducer = LeafNode; // A class signature `class C` -template +template struct ClassSignature { static constexpr auto Kind = KindT.Define( {.category = Category, .bracketed_by = ClassIntroducer::Kind}); @@ -1027,7 +1028,7 @@ struct BaseDecl { using InterfaceIntroducer = LeafNode; // `interface I` -template +template struct InterfaceSignature { static constexpr auto Kind = KindT.Define( {.category = Category, .bracketed_by = InterfaceIntroducer::Kind}); @@ -1080,7 +1081,7 @@ struct TypeImplAs { }; // `impl T as I` -template +template struct ImplSignature { static constexpr auto Kind = KindT.Define( {.category = Category, .bracketed_by = ImplIntroducer::Kind}); @@ -1115,7 +1116,7 @@ struct ImplDefinition { using NamedConstraintIntroducer = LeafNode; // `constraint NC` -template +template struct NamedConstraintSignature { static constexpr auto Kind = KindT.Define( {.category = Category, .bracketed_by = NamedConstraintIntroducer::Kind});