modifiers.cpp 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. // Part of the Carbon Language project, under the Apache License v2.0 with LLVM
  2. // Exceptions. See /LICENSE for license information.
  3. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  4. #include "toolchain/check/modifiers.h"
  5. #include "toolchain/check/decl_introducer_state.h"
  6. namespace Carbon::Check {
  7. // Returns the TokenKind for a DeclKind.
  8. static auto DeclKindToken(DeclIntroducerState::DeclKind decl_kind)
  9. -> Lex::TokenKind {
  10. switch (decl_kind) {
  11. case DeclIntroducerState::Adapt:
  12. return Lex::TokenKind::Adapt;
  13. case DeclIntroducerState::Alias:
  14. return Lex::TokenKind::Alias;
  15. case DeclIntroducerState::Base:
  16. return Lex::TokenKind::Base;
  17. case DeclIntroducerState::Class:
  18. return Lex::TokenKind::Class;
  19. case DeclIntroducerState::Constraint:
  20. return Lex::TokenKind::Constraint;
  21. case DeclIntroducerState::Export:
  22. return Lex::TokenKind::Export;
  23. case DeclIntroducerState::Fn:
  24. return Lex::TokenKind::Fn;
  25. case DeclIntroducerState::Import:
  26. return Lex::TokenKind::Import;
  27. case DeclIntroducerState::Impl:
  28. return Lex::TokenKind::Impl;
  29. case DeclIntroducerState::Interface:
  30. return Lex::TokenKind::Interface;
  31. case DeclIntroducerState::Let:
  32. return Lex::TokenKind::Let;
  33. case DeclIntroducerState::Library:
  34. return Lex::TokenKind::Library;
  35. case DeclIntroducerState::Namespace:
  36. return Lex::TokenKind::Namespace;
  37. case DeclIntroducerState::Package:
  38. return Lex::TokenKind::Package;
  39. case DeclIntroducerState::Var:
  40. return Lex::TokenKind::Var;
  41. }
  42. }
  43. static auto DiagnoseNotAllowed(Context& context, Parse::NodeId modifier_node,
  44. Lex::TokenKind decl_kind,
  45. llvm::StringRef context_string,
  46. SemIR::LocId context_loc_id) -> void {
  47. CARBON_DIAGNOSTIC(ModifierNotAllowedOn, Error,
  48. "`{0}` not allowed on `{1}` declaration{2}.",
  49. Lex::TokenKind, Lex::TokenKind, std::string);
  50. auto diag = context.emitter().Build(modifier_node, ModifierNotAllowedOn,
  51. context.token_kind(modifier_node),
  52. decl_kind, context_string.str());
  53. if (context_loc_id.is_valid()) {
  54. CARBON_DIAGNOSTIC(ModifierNotInContext, Note,
  55. "Containing definition here.");
  56. diag.Note(context_loc_id, ModifierNotInContext);
  57. }
  58. diag.Emit();
  59. }
  60. // Returns the KeywordModifierSet corresponding to the ModifierOrder entry.
  61. static auto ModifierOrderAsSet(ModifierOrder order) -> KeywordModifierSet {
  62. switch (order) {
  63. case ModifierOrder::Access:
  64. return KeywordModifierSet::Access;
  65. case ModifierOrder::Extern:
  66. return KeywordModifierSet::Extern;
  67. case ModifierOrder::Decl:
  68. return KeywordModifierSet::Decl;
  69. }
  70. }
  71. auto ForbidModifiersOnDecl(Context& context, DeclIntroducerState& introducer,
  72. KeywordModifierSet forbidden,
  73. llvm::StringRef context_string,
  74. SemIR::LocId context_loc_id) -> void {
  75. auto not_allowed = introducer.modifier_set & forbidden;
  76. if (not_allowed.empty()) {
  77. return;
  78. }
  79. for (auto order_index = 0;
  80. order_index <= static_cast<int8_t>(ModifierOrder::Last); ++order_index) {
  81. auto order = static_cast<ModifierOrder>(order_index);
  82. if (not_allowed.HasAnyOf(ModifierOrderAsSet(order))) {
  83. DiagnoseNotAllowed(context, introducer.modifier_node_id(order),
  84. DeclKindToken(introducer.kind), context_string,
  85. context_loc_id);
  86. introducer.set_modifier_node_id(order, Parse::NodeId::Invalid);
  87. }
  88. }
  89. introducer.modifier_set.Remove(forbidden);
  90. }
  91. auto CheckAccessModifiersOnDecl(Context& context,
  92. DeclIntroducerState& introducer,
  93. std::optional<SemIR::Inst> parent_scope_inst)
  94. -> void {
  95. if (parent_scope_inst) {
  96. if (parent_scope_inst->Is<SemIR::Namespace>()) {
  97. // TODO: This assumes that namespaces can only be declared at file scope.
  98. // If we add support for non-file-scope namespaces, we will need to check
  99. // the parents of the target scope to determine whether we're at file
  100. // scope.
  101. ForbidModifiersOnDecl(
  102. context, introducer, KeywordModifierSet::Protected,
  103. " at file scope, `protected` is only allowed on class members");
  104. return;
  105. }
  106. if (parent_scope_inst->Is<SemIR::ClassDecl>()) {
  107. // Both `private` and `protected` allowed in a class definition.
  108. return;
  109. }
  110. }
  111. // Otherwise neither `private` nor `protected` allowed.
  112. ForbidModifiersOnDecl(context, introducer, KeywordModifierSet::Protected,
  113. ", `protected` is only allowed on class members");
  114. ForbidModifiersOnDecl(
  115. context, introducer, KeywordModifierSet::Private,
  116. ", `private` is only allowed on class members and at file scope");
  117. }
  118. auto CheckMethodModifiersOnFunction(
  119. Context& context, DeclIntroducerState& introducer,
  120. SemIR::InstId parent_scope_inst_id,
  121. std::optional<SemIR::Inst> parent_scope_inst) -> void {
  122. if (parent_scope_inst) {
  123. if (auto class_decl = parent_scope_inst->TryAs<SemIR::ClassDecl>()) {
  124. auto inheritance_kind =
  125. context.classes().Get(class_decl->class_id).inheritance_kind;
  126. if (inheritance_kind == SemIR::Class::Final) {
  127. ForbidModifiersOnDecl(context, introducer, KeywordModifierSet::Virtual,
  128. " in a non-abstract non-base `class` definition",
  129. context.insts().GetLocId(parent_scope_inst_id));
  130. }
  131. if (inheritance_kind != SemIR::Class::Abstract) {
  132. ForbidModifiersOnDecl(context, introducer, KeywordModifierSet::Abstract,
  133. " in a non-abstract `class` definition",
  134. context.insts().GetLocId(parent_scope_inst_id));
  135. }
  136. return;
  137. }
  138. }
  139. ForbidModifiersOnDecl(context, introducer, KeywordModifierSet::Method,
  140. " outside of a class");
  141. }
  142. auto RestrictExternModifierOnDecl(Context& context,
  143. DeclIntroducerState& introducer,
  144. std::optional<SemIR::Inst> parent_scope_inst,
  145. bool is_definition) -> void {
  146. if (is_definition) {
  147. ForbidModifiersOnDecl(context, introducer, KeywordModifierSet::Extern,
  148. " that provides a definition");
  149. }
  150. if (parent_scope_inst && !parent_scope_inst->Is<SemIR::Namespace>()) {
  151. ForbidModifiersOnDecl(context, introducer, KeywordModifierSet::Extern,
  152. " that is a member");
  153. }
  154. }
  155. auto RequireDefaultFinalOnlyInInterfaces(
  156. Context& context, DeclIntroducerState& introducer,
  157. std::optional<SemIR::Inst> parent_scope_inst) -> void {
  158. if (parent_scope_inst && parent_scope_inst->Is<SemIR::InterfaceDecl>()) {
  159. // Both `default` and `final` allowed in an interface definition.
  160. return;
  161. }
  162. ForbidModifiersOnDecl(context, introducer, KeywordModifierSet::Interface,
  163. " outside of an interface");
  164. }
  165. } // namespace Carbon::Check