Files
carbon-lang/toolchain/check/keyword_modifier_set.h
T
Richard Smith 1b2ae912fc Add basic support for eval fn and musteval fn. (#6694)
Add support for compile-time functions. `eval fn` is analogous to C++
`constexpr`, and is evaluated at compile time when it has compile-time
arguments. `musteval fn` is analogous to C++ `consteval`, and requires
that its arguments be available at compile time and is always evaluated
at compile time. For now we require the modifier to match across
redeclarations of the function. The specific modifier syntax here is a
placeholder and not yet part of an approved design.

Limitations: Only very basic support for evaluation is provided. So far
there's no support for mutable state or `if` expressions, but otherwise
control flow and passing and returning values should work. Carbon
evaluation recursion is modeled by C++ recursion for now, so you can
overflow the toolchain stack easily. Functions that use in-place
initialization will generally not work yet, as they are modeled as
passing a non-compile-time-constant reference to a temporary to the
call.

Add missing categorization of `name_binding_decl` as `NotExpr` to match
other similar declaration instructions like `FunctionDecl`, so that we
can uniformly skip over them when they occur within function bodies.

Assisted-by: Gemini 3 Pro and Flash via Antigravity
2026-02-11 02:08:16 +00:00

167 lines
7.3 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 "common/enum_mask_base.h"
#include "toolchain/sem_ir/name_scope.h"
namespace Carbon::Check {
// 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,
Evaluation,
Last = Evaluation
};
// A single X-macro to cover modifier groups. These are split out to make groups
// clearer.
#define CARBON_KEYWORD_MODIFIER_SET(X) \
/* At most one of these access modifiers allowed for a given declaration, \
* and if present it must be first. */ \
X(Private) \
X(Protected) \
\
/* Extern is standalone. */ \
X(Extern) \
\
/* Extend can be combined with Final, but no others in the group below. */ \
X(Extend) \
\
/* At most one of these declaration modifiers allowed for a given \
* declaration. */ \
X(Abstract) \
X(Base) \
X(Default) \
X(Export) \
X(Final) \
X(Impl) \
X(Override) \
X(Returned) \
X(Virtual) \
\
/* Eval and MustEval are mutually exclusive. */ \
X(Eval) \
X(MustEval)
// We expect this to grow, so are using a bigger size than needed.
CARBON_DEFINE_RAW_ENUM_MASK(KeywordModifierSet, uint32_t) {
CARBON_KEYWORD_MODIFIER_SET(CARBON_RAW_ENUM_MASK_ENUMERATOR)
};
// Represents a set of keyword modifiers, using a separate bit per modifier.
class KeywordModifierSet : public CARBON_ENUM_MASK_BASE(KeywordModifierSet) {
public:
CARBON_KEYWORD_MODIFIER_SET(CARBON_ENUM_MASK_CONSTANT_DECL)
// Sets of modifiers.
static const KeywordModifierSet Access;
static const KeywordModifierSet Class;
static const KeywordModifierSet Method;
static const KeywordModifierSet ImplDecl;
static const KeywordModifierSet Interface;
static const KeywordModifierSet Evaluation;
static const KeywordModifierSet Decl;
// 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(KeywordModifierSet other, T result) -> Converter& {
if (set_.HasAnyOf(other)) {
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;
}
};
#define CARBON_KEYWORD_MODIFIER_SET_WITH_TYPE(X) \
CARBON_ENUM_MASK_CONSTANT_DEFINITION(KeywordModifierSet, X)
CARBON_KEYWORD_MODIFIER_SET(CARBON_KEYWORD_MODIFIER_SET_WITH_TYPE)
#undef CARBON_KEYWORD_MODIFIER_SET_WITH_TYPE
inline constexpr KeywordModifierSet KeywordModifierSet::Access(Private |
Protected);
inline constexpr KeywordModifierSet KeywordModifierSet::Class(Abstract | Base);
inline constexpr KeywordModifierSet KeywordModifierSet::Method(Abstract |
Override |
Virtual);
inline constexpr KeywordModifierSet KeywordModifierSet::ImplDecl(Extend |
Final);
inline constexpr KeywordModifierSet KeywordModifierSet::Interface(Default |
Final);
inline constexpr KeywordModifierSet KeywordModifierSet::Decl(Class | Method |
Impl | Interface |
Export | Returned);
inline constexpr KeywordModifierSet KeywordModifierSet::Evaluation(Eval |
MustEval);
// TODO: This and the ordering checking logic in handle_modifiers.cpp are
// becoming unwieldy. Find a better representation.
static_assert(
!KeywordModifierSet::Access.HasAnyOf(KeywordModifierSet::Extern) &&
!(KeywordModifierSet::Access | KeywordModifierSet::Extern |
KeywordModifierSet::Extend)
.HasAnyOf(KeywordModifierSet::Decl) &&
!(KeywordModifierSet::Access | KeywordModifierSet::Extern |
KeywordModifierSet::Decl)
.HasAnyOf(KeywordModifierSet::Evaluation),
"Order-related sets must not overlap");
#define CARBON_KEYWORD_MODIFIER_SET_IN_GROUP(Modifier) \
static_assert((KeywordModifierSet::Access | KeywordModifierSet::Extern | \
KeywordModifierSet::Extend | KeywordModifierSet::Decl | \
KeywordModifierSet::Evaluation) \
.HasAnyOf(KeywordModifierSet::Modifier), \
"Modifier missing from all modifier sets: " #Modifier);
CARBON_KEYWORD_MODIFIER_SET(CARBON_KEYWORD_MODIFIER_SET_IN_GROUP)
#undef CARBON_KEYWORD_MODIFIER_SET_IN_GROUP
} // namespace Carbon::Check
#endif // CARBON_TOOLCHAIN_CHECK_KEYWORD_MODIFIER_SET_H_