Files
carbon-lang/toolchain/check/modifiers.cpp
T
josh11b 3b0923c81d Add interface support to check (#3474)
Largely copied from the `class` code
2023-12-08 17:13:49 +00:00

98 lines
3.9 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
#include "toolchain/check/modifiers.h"
namespace Carbon::Check {
static auto ReportNotAllowed(Context& context, Parse::NodeId modifier_node,
Lex::TokenKind decl_kind,
llvm::StringRef context_string,
Parse::NodeId context_node) -> void {
CARBON_DIAGNOSTIC(ModifierNotAllowedOn, Error,
"`{0}` not allowed on `{1}` declaration{2}.",
Lex::TokenKind, Lex::TokenKind, std::string);
auto diag = context.emitter().Build(modifier_node, ModifierNotAllowedOn,
context.token_kind(modifier_node),
decl_kind, context_string.str());
if (context_node.is_valid()) {
CARBON_DIAGNOSTIC(ModifierNotInContext, Note,
"Containing definition here.");
diag.Note(context_node, ModifierNotInContext);
}
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;
}
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,
Lex::TokenKind decl_kind,
llvm::StringRef context_string,
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) {
ReportNotAllowed(context, s.saw_decl_modifier, decl_kind, context_string,
context_node);
s.saw_decl_modifier = Parse::NodeId::Invalid;
}
s.modifier_set = s.modifier_set & ~forbidden;
}
auto CheckAccessModifiersOnDecl(Context& context, Lex::TokenKind decl_kind)
-> void {
if (context.at_file_scope()) {
ForbidModifiersOnDecl(
context, KeywordModifierSet::Protected, decl_kind,
" at file scope, `protected` is only allowed on class members");
return;
}
if (context.CurrentScopeIs<SemIR::ClassDecl>()) {
// Both `private` and `protected` allowed in a class definition.
return;
}
// Otherwise neither `private` nor `protected` allowed.
ForbidModifiersOnDecl(context, KeywordModifierSet::Protected, decl_kind,
", `protected` is only allowed on class members");
ForbidModifiersOnDecl(
context, KeywordModifierSet::Private, decl_kind,
", `private` is only allowed on class members and at file scope");
}
auto RequireDefaultFinalOnlyInInterfaces(Context& context,
Lex::TokenKind decl_kind) -> void {
if (context.CurrentScopeIs<SemIR::InterfaceDecl>()) {
// Both `default` and `final` allowed in an interface definition.
return;
}
ForbidModifiersOnDecl(context, KeywordModifierSet::Interface, decl_kind,
" outside of an interface");
}
} // namespace Carbon::Check