mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-04 22:02:52 +01:00
Switch decl_state to an arg for modifier functions (#4027)
With private modifiers, we'll want to start checking modifiers later, e.g. after a name conflict is detected (and potentially merged). I think we've agreed to be more explicit about whether the modifier functions are manipulating state, versus trying to keep the state on the stack a little longer (moving Pop to the end of these functions). Removing FileScope from the stack and renaming it to DeclIntroducerStack to better reflect the usage and behavior. The FileScope mostly reflects an approach that wasn't ultimately adopted.
This commit is contained in:
@@ -4,7 +4,7 @@
|
||||
|
||||
#include "toolchain/check/modifiers.h"
|
||||
|
||||
#include "toolchain/check/decl_state.h"
|
||||
#include "toolchain/check/decl_introducer_state.h"
|
||||
|
||||
namespace Carbon::Check {
|
||||
|
||||
@@ -38,12 +38,12 @@ static auto ModifierOrderAsSet(ModifierOrder order) -> KeywordModifierSet {
|
||||
}
|
||||
}
|
||||
|
||||
auto ForbidModifiersOnDecl(Context& context, KeywordModifierSet forbidden,
|
||||
auto ForbidModifiersOnDecl(Context& context, DeclIntroducerState& introducer,
|
||||
KeywordModifierSet forbidden,
|
||||
Lex::TokenKind decl_kind,
|
||||
llvm::StringRef context_string,
|
||||
SemIR::LocId context_loc_id) -> void {
|
||||
auto& s = context.decl_state_stack().innermost();
|
||||
auto not_allowed = s.modifier_set & forbidden;
|
||||
auto not_allowed = introducer.modifier_set & forbidden;
|
||||
if (not_allowed.empty()) {
|
||||
return;
|
||||
}
|
||||
@@ -52,16 +52,18 @@ auto ForbidModifiersOnDecl(Context& context, KeywordModifierSet forbidden,
|
||||
order_index <= static_cast<int8_t>(ModifierOrder::Last); ++order_index) {
|
||||
auto order = static_cast<ModifierOrder>(order_index);
|
||||
if (not_allowed.HasAnyOf(ModifierOrderAsSet(order))) {
|
||||
DiagnoseNotAllowed(context, s.modifier_node_id(order), decl_kind,
|
||||
DiagnoseNotAllowed(context, introducer.modifier_node_id(order), decl_kind,
|
||||
context_string, context_loc_id);
|
||||
s.set_modifier_node_id(order, Parse::NodeId::Invalid);
|
||||
introducer.set_modifier_node_id(order, Parse::NodeId::Invalid);
|
||||
}
|
||||
}
|
||||
|
||||
s.modifier_set.Remove(forbidden);
|
||||
introducer.modifier_set.Remove(forbidden);
|
||||
}
|
||||
|
||||
auto CheckAccessModifiersOnDecl(Context& context, Lex::TokenKind decl_kind,
|
||||
auto CheckAccessModifiersOnDecl(Context& context,
|
||||
DeclIntroducerState& introducer,
|
||||
Lex::TokenKind decl_kind,
|
||||
std::optional<SemIR::Inst> parent_scope_inst)
|
||||
-> void {
|
||||
if (parent_scope_inst) {
|
||||
@@ -71,7 +73,7 @@ auto CheckAccessModifiersOnDecl(Context& context, Lex::TokenKind decl_kind,
|
||||
// the parents of the target scope to determine whether we're at file
|
||||
// scope.
|
||||
ForbidModifiersOnDecl(
|
||||
context, KeywordModifierSet::Protected, decl_kind,
|
||||
context, introducer, KeywordModifierSet::Protected, decl_kind,
|
||||
" at file scope, `protected` is only allowed on class members");
|
||||
return;
|
||||
}
|
||||
@@ -83,15 +85,17 @@ auto CheckAccessModifiersOnDecl(Context& context, Lex::TokenKind decl_kind,
|
||||
}
|
||||
|
||||
// Otherwise neither `private` nor `protected` allowed.
|
||||
ForbidModifiersOnDecl(context, KeywordModifierSet::Protected, decl_kind,
|
||||
ForbidModifiersOnDecl(context, introducer, KeywordModifierSet::Protected,
|
||||
decl_kind,
|
||||
", `protected` is only allowed on class members");
|
||||
ForbidModifiersOnDecl(
|
||||
context, KeywordModifierSet::Private, decl_kind,
|
||||
context, introducer, KeywordModifierSet::Private, decl_kind,
|
||||
", `private` is only allowed on class members and at file scope");
|
||||
}
|
||||
|
||||
auto CheckMethodModifiersOnFunction(
|
||||
Context& context, SemIR::InstId parent_scope_inst_id,
|
||||
Context& context, DeclIntroducerState& introducer,
|
||||
SemIR::InstId parent_scope_inst_id,
|
||||
std::optional<SemIR::Inst> parent_scope_inst) -> void {
|
||||
const Lex::TokenKind decl_kind = Lex::TokenKind::Fn;
|
||||
if (parent_scope_inst) {
|
||||
@@ -99,12 +103,14 @@ auto CheckMethodModifiersOnFunction(
|
||||
auto inheritance_kind =
|
||||
context.classes().Get(class_decl->class_id).inheritance_kind;
|
||||
if (inheritance_kind == SemIR::Class::Final) {
|
||||
ForbidModifiersOnDecl(context, KeywordModifierSet::Virtual, decl_kind,
|
||||
ForbidModifiersOnDecl(context, introducer, KeywordModifierSet::Virtual,
|
||||
decl_kind,
|
||||
" in a non-abstract non-base `class` definition",
|
||||
context.insts().GetLocId(parent_scope_inst_id));
|
||||
}
|
||||
if (inheritance_kind != SemIR::Class::Abstract) {
|
||||
ForbidModifiersOnDecl(context, KeywordModifierSet::Abstract, decl_kind,
|
||||
ForbidModifiersOnDecl(context, introducer, KeywordModifierSet::Abstract,
|
||||
decl_kind,
|
||||
" in a non-abstract `class` definition",
|
||||
context.insts().GetLocId(parent_scope_inst_id));
|
||||
}
|
||||
@@ -112,32 +118,34 @@ auto CheckMethodModifiersOnFunction(
|
||||
}
|
||||
}
|
||||
|
||||
ForbidModifiersOnDecl(context, KeywordModifierSet::Method, decl_kind,
|
||||
" outside of a class");
|
||||
ForbidModifiersOnDecl(context, introducer, KeywordModifierSet::Method,
|
||||
decl_kind, " outside of a class");
|
||||
}
|
||||
|
||||
auto RestrictExternModifierOnDecl(Context& context, Lex::TokenKind decl_kind,
|
||||
auto RestrictExternModifierOnDecl(Context& context,
|
||||
DeclIntroducerState& introducer,
|
||||
Lex::TokenKind decl_kind,
|
||||
std::optional<SemIR::Inst> parent_scope_inst,
|
||||
bool is_definition) -> void {
|
||||
if (is_definition) {
|
||||
ForbidModifiersOnDecl(context, KeywordModifierSet::Extern, decl_kind,
|
||||
" that provides a definition");
|
||||
ForbidModifiersOnDecl(context, introducer, KeywordModifierSet::Extern,
|
||||
decl_kind, " that provides a definition");
|
||||
}
|
||||
if (parent_scope_inst && !parent_scope_inst->Is<SemIR::Namespace>()) {
|
||||
ForbidModifiersOnDecl(context, KeywordModifierSet::Extern, decl_kind,
|
||||
" that is a member");
|
||||
ForbidModifiersOnDecl(context, introducer, KeywordModifierSet::Extern,
|
||||
decl_kind, " that is a member");
|
||||
}
|
||||
}
|
||||
|
||||
auto RequireDefaultFinalOnlyInInterfaces(
|
||||
Context& context, Lex::TokenKind decl_kind,
|
||||
Context& context, DeclIntroducerState& introducer, Lex::TokenKind decl_kind,
|
||||
std::optional<SemIR::Inst> parent_scope_inst) -> void {
|
||||
if (parent_scope_inst && parent_scope_inst->Is<SemIR::InterfaceDecl>()) {
|
||||
// Both `default` and `final` allowed in an interface definition.
|
||||
return;
|
||||
}
|
||||
ForbidModifiersOnDecl(context, KeywordModifierSet::Interface, decl_kind,
|
||||
" outside of an interface");
|
||||
ForbidModifiersOnDecl(context, introducer, KeywordModifierSet::Interface,
|
||||
decl_kind, " outside of an interface");
|
||||
}
|
||||
|
||||
} // namespace Carbon::Check
|
||||
|
||||
Reference in New Issue
Block a user