Add framework for the extern keyword. (#3755)

This doesn't add full support. I'm separating it out to make the effects
of the modifier changes clearer for review. I'm restructuring a little
with the expectation that we'll have some more categories of modifier
keywords in the future (similar to `extern`, these may not be in a "set"
such as access), and thus easily scaling up to a few more would be
useful.
This commit is contained in:
Jon Ross-Perkins
2024-03-08 16:01:12 +00:00
committed by GitHub
parent 56d70dc3a2
commit 096daecc57
21 changed files with 241 additions and 102 deletions
+26 -28
View File
@@ -4,6 +4,8 @@
#include "toolchain/check/modifiers.h"
#include "toolchain/check/decl_state.h"
namespace Carbon::Check {
static auto ReportNotAllowed(Context& context, Parse::NodeId modifier_node,
@@ -24,22 +26,16 @@ static auto ReportNotAllowed(Context& context, Parse::NodeId modifier_node,
diag.Emit();
}
auto LimitModifiersOnDecl(Context& context, KeywordModifierSet allowed,
Lex::TokenKind decl_kind) -> void {
auto& s = context.decl_state_stack().innermost();
auto not_allowed = s.modifier_set & ~allowed;
if (!!(not_allowed & KeywordModifierSet::Access)) {
ReportNotAllowed(context, s.saw_access_modifier, decl_kind, "",
Parse::NodeId::Invalid);
not_allowed = not_allowed & ~KeywordModifierSet::Access;
s.saw_access_modifier = Parse::NodeId::Invalid;
// Returns the KeywordModifierSet corresponding to the ModifierOrder entry.
static auto ModifierOrderAsSet(ModifierOrder order) -> KeywordModifierSet {
switch (order) {
case ModifierOrder::Access:
return KeywordModifierSet::Access;
case ModifierOrder::Extern:
return KeywordModifierSet::Extern;
case ModifierOrder::Decl:
return KeywordModifierSet::Decl;
}
if (!!not_allowed) {
ReportNotAllowed(context, s.saw_decl_modifier, decl_kind, "",
Parse::NodeId::Invalid);
s.saw_decl_modifier = Parse::NodeId::Invalid;
}
s.modifier_set &= allowed;
}
auto ForbidModifiersOnDecl(Context& context, KeywordModifierSet forbidden,
@@ -48,23 +44,26 @@ auto ForbidModifiersOnDecl(Context& context, KeywordModifierSet forbidden,
Parse::NodeId context_node) -> void {
auto& s = context.decl_state_stack().innermost();
auto not_allowed = s.modifier_set & forbidden;
if (!!(not_allowed & KeywordModifierSet::Access)) {
ReportNotAllowed(context, s.saw_access_modifier, decl_kind, context_string,
context_node);
not_allowed = not_allowed & ~KeywordModifierSet::Access;
s.saw_access_modifier = Parse::NodeId::Invalid;
if (!not_allowed) {
return;
}
if (!!not_allowed) {
ReportNotAllowed(context, s.saw_decl_modifier, decl_kind, context_string,
context_node);
s.saw_decl_modifier = Parse::NodeId::Invalid;
for (auto order_index = 0;
order_index <= static_cast<int8_t>(ModifierOrder::Last); ++order_index) {
auto order = static_cast<ModifierOrder>(order_index);
if (!!(not_allowed & ModifierOrderAsSet(order))) {
ReportNotAllowed(context, s.modifier_node_id(order), decl_kind,
context_string, context_node);
s.set_modifier_node_id(order, Parse::NodeId::Invalid);
}
}
s.modifier_set = s.modifier_set & ~forbidden;
s.modifier_set &= ~forbidden;
}
// Returns the instruction that owns the given scope, or Invalid if the scope is
// not associated with an instruction.
auto GetScopeInstId(Context& context, SemIR::NameScopeId scope_id)
static auto GetScopeInstId(Context& context, SemIR::NameScopeId scope_id)
-> SemIR::InstId {
if (!scope_id.is_valid()) {
return SemIR::InstId::Invalid;
@@ -74,7 +73,7 @@ auto GetScopeInstId(Context& context, SemIR::NameScopeId scope_id)
// Returns the instruction that owns the given scope, or Invalid if the scope is
// not associated with an instruction.
auto GetScopeInst(Context& context, SemIR::NameScopeId scope_id)
static auto GetScopeInst(Context& context, SemIR::NameScopeId scope_id)
-> std::optional<SemIR::Inst> {
auto inst_id = GetScopeInstId(context, scope_id);
if (!inst_id.is_valid()) {
@@ -109,7 +108,6 @@ auto CheckAccessModifiersOnDecl(Context& context, Lex::TokenKind decl_kind,
", `private` is only allowed on class members and at file scope");
}
// Rules for abstract, virtual, and impl, which are only allowed in classes.
auto CheckMethodModifiersOnFunction(Context& context,
SemIR::NameScopeId target_scope_id)
-> void {