Files
carbon-lang/toolchain/check/keyword_modifier_set.h
T
josh11bandJosh L c455dbef54 Clean up KeywordModifierSet after #5345 (#5425)
See comment
https://github.com/carbon-language/carbon-lang/pull/5345#discussion_r2074260967

> `Impl` is already a part of `Method` and refers to using `impl` as a
modifier keyword on virtual methods (to be replaced by `override`, see
#5253 ), as opposed to `ImplDecl` which is the modifiers allowed on an
`impl` declaration. It would make more sense to delete this than use
`Impl` here.

Co-authored-by: Josh L <josh11b@users.noreply.github.com>
2025-05-06 16:56:06 +00:00

158 lines
5.0 KiB
C++

// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
// Exceptions. See /LICENSE for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#ifndef CARBON_TOOLCHAIN_CHECK_KEYWORD_MODIFIER_SET_H_
#define CARBON_TOOLCHAIN_CHECK_KEYWORD_MODIFIER_SET_H_
#include <optional>
#include "llvm/ADT/BitmaskEnum.h"
#include "toolchain/sem_ir/name_scope.h"
namespace Carbon::Check {
LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE();
// The order of modifiers. Each of these corresponds to a group on
// KeywordModifierSet, and can be used as an array index.
enum class ModifierOrder : int8_t { Access, Extern, Extend, Decl, Last = Decl };
// Represents a set of keyword modifiers, using a separate bit per modifier.
class KeywordModifierSet {
public:
// Provide values as an enum. This doesn't expose these as KeywordModifierSet
// instances just due to the duplication of declarations that would cause.
//
// We expect this to grow, so are using a bigger size than needed.
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,
Protected = 1 << 1,
// Extern is standalone.
Extern = 1 << 2,
// Extend can be combined with Final, but no others in the group below.
Extend = 1 << 3,
// At most one of these declaration modifiers allowed for a given
// declaration:
Abstract = 1 << 4,
Base = 1 << 5,
Default = 1 << 6,
Export = 1 << 7,
Final = 1 << 8,
Impl = 1 << 9,
Virtual = 1 << 10,
Returned = 1 << 11,
// Sets of modifiers:
Access = Private | Protected,
Class = Abstract | Base,
Method = Abstract | Impl | Virtual,
ImplDecl = Extend | Final,
Interface = Default | Final,
Decl = Class | Method | Interface | Export | Returned,
None = 0,
LLVM_MARK_AS_BITMASK_ENUM(/*LargestValue=*/Returned)
};
// Default construct to empty.
explicit KeywordModifierSet() : set_(None) {}
// Support implicit conversion so that the difference with the member enum is
// opaque.
// NOLINTNEXTLINE(google-explicit-constructor)
constexpr KeywordModifierSet(RawEnumType set) : set_(set) {}
// Adds entries to the set.
auto Add(KeywordModifierSet set) -> void { set_ |= set.set_; }
// Removes entries from the set.
auto Remove(KeywordModifierSet set) -> void { set_ &= ~set.set_; }
// Returns true if there's a non-empty set intersection.
constexpr auto HasAnyOf(KeywordModifierSet other) const -> bool {
return set_ & other.set_;
}
// Return a builder that returns the new enumeration type once a series of
// mapping `Case`s and a final `Default` are provided. For example:
// ```
// auto e = set.ToEnum<SomeEnum>()
// .Case(KeywordModifierSet::A, SomeEnum::A)
// .Case(KeywordModifierSet::B, SomeEnum::B)
// .Default(SomeEnum::DefaultValue);
// ```
template <typename T>
auto ToEnum() const -> auto {
class Converter {
public:
explicit Converter(const KeywordModifierSet& set) : set_(set) {}
auto Case(RawEnumType raw_enumerator, T result) -> Converter& {
if (set_.HasAnyOf(raw_enumerator)) {
result_ = result;
}
return *this;
}
auto Default(T default_value) -> T {
if (result_) {
return *result_;
}
return default_value;
}
private:
const KeywordModifierSet& set_;
std::optional<T> result_;
};
return Converter(*this);
}
// Returns the access kind from modifiers.
auto GetAccessKind() const -> SemIR::AccessKind {
if (HasAnyOf(KeywordModifierSet::Protected)) {
return SemIR::AccessKind::Protected;
}
if (HasAnyOf(KeywordModifierSet::Private)) {
return SemIR::AccessKind::Private;
}
return SemIR::AccessKind::Public;
}
// Returns true if empty.
constexpr auto empty() const -> bool { return !set_; }
// Returns the set intersection.
constexpr auto operator&(KeywordModifierSet other) const
-> KeywordModifierSet {
return set_ & other.set_;
}
// Returns the set inverse.
auto operator~() const -> KeywordModifierSet { return ~set_; }
private:
RawEnumType set_;
};
static_assert(!KeywordModifierSet(KeywordModifierSet::Access)
.HasAnyOf(KeywordModifierSet::Extern) &&
!KeywordModifierSet(KeywordModifierSet::Access |
KeywordModifierSet::Extern |
KeywordModifierSet::Extend)
.HasAnyOf(KeywordModifierSet::Decl),
"Order-related sets must not overlap");
static_assert(~KeywordModifierSet::None ==
(KeywordModifierSet::Access | KeywordModifierSet::Extern |
KeywordModifierSet::Extend | KeywordModifierSet::Decl),
"Modifier missing from all modifier sets");
} // namespace Carbon::Check
#endif // CARBON_TOOLCHAIN_CHECK_KEYWORD_MODIFIER_SET_H_