overload_resolution.cpp 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  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/cpp/overload_resolution.h"
  5. #include "clang/Basic/DiagnosticSema.h"
  6. #include "clang/Sema/Overload.h"
  7. #include "clang/Sema/Sema.h"
  8. #include "toolchain/base/kind_switch.h"
  9. #include "toolchain/check/cpp/import.h"
  10. #include "toolchain/check/cpp/location.h"
  11. #include "toolchain/check/cpp/operators.h"
  12. #include "toolchain/check/cpp/type_mapping.h"
  13. #include "toolchain/check/member_access.h"
  14. #include "toolchain/check/name_lookup.h"
  15. #include "toolchain/diagnostics/diagnostic_emitter.h"
  16. #include "toolchain/sem_ir/function.h"
  17. #include "toolchain/sem_ir/ids.h"
  18. #include "toolchain/sem_ir/name_scope.h"
  19. #include "toolchain/sem_ir/typed_insts.h"
  20. namespace Carbon::Check {
  21. // Map a Carbon name into a C++ name.
  22. static auto GetCppName(Context& context, SemIR::NameId name_id)
  23. -> clang::DeclarationName {
  24. // TODO: Some special names should probably use different formatting. In
  25. // particular, NameId::CppOperator should probably map back to a
  26. // CXXOperatorName.
  27. auto name_str = context.names().GetFormatted(name_id);
  28. return clang::DeclarationName(&context.ast_context().Idents.get(name_str));
  29. }
  30. // Adds the given overload candidates to the candidate set.
  31. static auto AddOverloadCandidataes(clang::Sema& sema,
  32. clang::OverloadCandidateSet& candidate_set,
  33. const clang::UnresolvedSetImpl& functions,
  34. clang::Expr* self_arg,
  35. llvm::ArrayRef<clang::Expr*> args) -> void {
  36. constexpr bool SuppressUserConversions = false;
  37. constexpr bool PartialOverloading = false;
  38. constexpr clang::TemplateArgumentListInfo* ExplicitTemplateArgs = nullptr;
  39. for (auto found_decl : functions.pairs()) {
  40. auto* decl = found_decl.getDecl()->getUnderlyingDecl();
  41. auto* template_decl = dyn_cast<clang::FunctionTemplateDecl>(decl);
  42. auto* fn_decl = template_decl ? template_decl->getTemplatedDecl()
  43. : cast<clang::FunctionDecl>(decl);
  44. auto* method_decl = dyn_cast<clang::CXXMethodDecl>(fn_decl);
  45. if (method_decl && !method_decl->isStatic() &&
  46. !isa<clang::CXXConstructorDecl>(fn_decl)) {
  47. clang::QualType self_type;
  48. clang::Expr::Classification self_classification;
  49. if (self_arg) {
  50. self_type = self_arg->getType();
  51. self_classification = self_arg->Classify(sema.Context);
  52. }
  53. if (template_decl) {
  54. sema.AddMethodTemplateCandidate(
  55. template_decl, found_decl,
  56. cast<clang::CXXRecordDecl>(template_decl->getDeclContext()),
  57. ExplicitTemplateArgs, self_type, self_classification, args,
  58. candidate_set, SuppressUserConversions, PartialOverloading);
  59. } else if (method_decl->isOverloadedOperator()) {
  60. sema.AddMemberOperatorCandidates(method_decl->getOverloadedOperator(),
  61. candidate_set.getLocation(), args,
  62. candidate_set);
  63. } else {
  64. sema.AddMethodCandidate(method_decl, found_decl,
  65. method_decl->getParent(), self_type,
  66. self_classification, args, candidate_set,
  67. SuppressUserConversions, PartialOverloading);
  68. }
  69. } else if (template_decl) {
  70. sema.AddTemplateOverloadCandidate(
  71. template_decl, found_decl, ExplicitTemplateArgs, args, candidate_set,
  72. SuppressUserConversions, PartialOverloading);
  73. } else {
  74. sema.AddOverloadCandidate(fn_decl, found_decl, args, candidate_set,
  75. SuppressUserConversions, PartialOverloading);
  76. }
  77. }
  78. }
  79. // Checks whether a selected overload is accessible and diagnoses if not.
  80. static auto CheckOverloadAccess(Context& context, SemIR::LocId loc_id,
  81. const SemIR::CppOverloadSet& overload_set,
  82. clang::DeclAccessPair overload,
  83. SemIR::InstId overload_inst_id) -> void {
  84. SemIR::AccessKind member_access_kind;
  85. switch (overload->getAccess()) {
  86. case clang::AS_none:
  87. case clang::AS_public: {
  88. return;
  89. }
  90. case clang::AS_protected: {
  91. member_access_kind = SemIR::AccessKind::Protected;
  92. break;
  93. }
  94. case clang::AS_private: {
  95. member_access_kind = SemIR::AccessKind::Private;
  96. break;
  97. }
  98. }
  99. auto name_scope_const_id = context.constant_values().Get(
  100. context.name_scopes().Get(overload_set.parent_scope_id).inst_id());
  101. SemIR::AccessKind allowed_access_kind =
  102. GetHighestAllowedAccess(context, loc_id, name_scope_const_id);
  103. CheckAccess(context, loc_id, SemIR::LocId(overload_inst_id),
  104. overload_set.name_id, member_access_kind,
  105. /*is_parent_access=*/false,
  106. {.constant_id = name_scope_const_id,
  107. .highest_allowed_access = allowed_access_kind});
  108. }
  109. auto PerformCppOverloadResolution(Context& context, SemIR::LocId loc_id,
  110. SemIR::CppOverloadSetId overload_set_id,
  111. SemIR::InstId self_id,
  112. llvm::ArrayRef<SemIR::InstId> arg_ids)
  113. -> SemIR::InstId {
  114. // Register an annotation scope to flush any Clang diagnostics when we return.
  115. // This is important to ensure that Clang diagnostics are properly interleaved
  116. // with Carbon diagnostics.
  117. Diagnostics::AnnotationScope annotate_diagnostics(&context.emitter(),
  118. [](auto& /*builder*/) {});
  119. // Map Carbon call argument types to C++ types.
  120. clang::Expr* self_expr = nullptr;
  121. if (self_id.has_value()) {
  122. self_expr = InventClangArg(context, self_id);
  123. if (!self_expr) {
  124. return SemIR::ErrorInst::InstId;
  125. }
  126. }
  127. auto maybe_arg_exprs = InventClangArgs(context, arg_ids);
  128. if (!maybe_arg_exprs.has_value()) {
  129. return SemIR::ErrorInst::InstId;
  130. }
  131. auto& arg_exprs = *maybe_arg_exprs;
  132. const SemIR::CppOverloadSet& overload_set =
  133. context.cpp_overload_sets().Get(overload_set_id);
  134. clang::SourceLocation loc = GetCppLocation(context, loc_id);
  135. // Add candidate functions from the name lookup.
  136. clang::OverloadCandidateSet candidate_set(
  137. loc, clang::OverloadCandidateSet::CandidateSetKind::CSK_Normal);
  138. clang::Sema& sema = context.clang_sema();
  139. AddOverloadCandidataes(sema, candidate_set, overload_set.candidate_functions,
  140. self_expr, arg_exprs);
  141. // Find best viable function among the candidates.
  142. clang::OverloadCandidateSet::iterator best_viable_fn;
  143. clang::OverloadingResult overloading_result =
  144. candidate_set.BestViableFunction(sema, loc, best_viable_fn);
  145. switch (overloading_result) {
  146. case clang::OverloadingResult::OR_Success: {
  147. // TODO: Handle the cases when Function is null.
  148. CARBON_CHECK(best_viable_fn->Function);
  149. sema.MarkFunctionReferenced(loc, best_viable_fn->Function);
  150. SemIR::InstId result_id = ImportCppFunctionDecl(
  151. context, loc_id, best_viable_fn->Function,
  152. // If this is an operator method, the first arg will be used as self.
  153. arg_exprs.size() -
  154. (IsCppOperatorMethodDecl(best_viable_fn->Function) ? 1 : 0));
  155. CheckOverloadAccess(context, loc_id, overload_set,
  156. best_viable_fn->FoundDecl, result_id);
  157. return result_id;
  158. }
  159. case clang::OverloadingResult::OR_No_Viable_Function: {
  160. candidate_set.NoteCandidates(
  161. clang::PartialDiagnosticAt(
  162. loc, sema.PDiag(clang::diag::err_ovl_no_viable_function_in_call)
  163. << GetCppName(context, overload_set.name_id)),
  164. sema, clang::OCD_AllCandidates, arg_exprs);
  165. return SemIR::ErrorInst::InstId;
  166. }
  167. case clang::OverloadingResult::OR_Ambiguous: {
  168. candidate_set.NoteCandidates(
  169. clang::PartialDiagnosticAt(
  170. loc, sema.PDiag(clang::diag::err_ovl_ambiguous_call)
  171. << GetCppName(context, overload_set.name_id)),
  172. sema, clang::OCD_AmbiguousCandidates, arg_exprs);
  173. return SemIR::ErrorInst::InstId;
  174. }
  175. case clang::OverloadingResult::OR_Deleted: {
  176. sema.DiagnoseUseOfDeletedFunction(
  177. loc, clang::SourceRange(loc, loc),
  178. GetCppName(context, overload_set.name_id), candidate_set,
  179. best_viable_fn->Function, arg_exprs);
  180. return SemIR::ErrorInst::InstId;
  181. }
  182. }
  183. }
  184. } // namespace Carbon::Check