overload_resolution.cpp 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  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/access.h"
  10. #include "toolchain/check/cpp/call.h"
  11. #include "toolchain/check/cpp/import.h"
  12. #include "toolchain/check/cpp/location.h"
  13. #include "toolchain/check/cpp/operators.h"
  14. #include "toolchain/check/cpp/type_mapping.h"
  15. #include "toolchain/check/member_access.h"
  16. #include "toolchain/check/name_lookup.h"
  17. #include "toolchain/diagnostics/emitter.h"
  18. #include "toolchain/sem_ir/function.h"
  19. #include "toolchain/sem_ir/ids.h"
  20. #include "toolchain/sem_ir/name_scope.h"
  21. #include "toolchain/sem_ir/typed_insts.h"
  22. namespace Carbon::Check {
  23. // Map a Carbon name into a C++ name.
  24. static auto GetCppName(Context& context, SemIR::NameId name_id)
  25. -> clang::DeclarationName {
  26. // TODO: Some special names should probably use different formatting. In
  27. // particular, NameId::CppOperator should probably map back to a
  28. // CXXOperatorName.
  29. auto name_str = context.names().GetFormatted(name_id);
  30. return clang::DeclarationName(&context.ast_context().Idents.get(name_str));
  31. }
  32. // Adds the given overload candidates to the candidate set.
  33. static auto AddOverloadCandidates(
  34. Context& context, clang::OverloadCandidateSet& candidate_set,
  35. const clang::UnresolvedSet<4>& functions,
  36. llvm::ArrayRef<SemIR::InstId> template_arg_ids, clang::Expr* self_arg,
  37. llvm::ArrayRef<clang::Expr*> args) -> void {
  38. clang::Sema& sema = context.clang_sema();
  39. constexpr bool SuppressUserConversions = false;
  40. constexpr bool PartialOverloading = false;
  41. for (auto found_decl : functions.pairs()) {
  42. auto* decl = found_decl->getUnderlyingDecl();
  43. // Form an explicit template argument list if needed. Note that this is done
  44. // per-candidate, as the conversions performed on the template arguments
  45. // differ based on the corresponding template parameters.
  46. auto* template_decl = dyn_cast<clang::FunctionTemplateDecl>(decl);
  47. clang::TemplateArgumentListInfo explicit_template_arg_storage;
  48. clang::TemplateArgumentListInfo* explicit_template_args = nullptr;
  49. if (!template_arg_ids.empty()) {
  50. if (!template_decl) {
  51. continue;
  52. }
  53. if (!ConvertArgsToTemplateArgs(context, template_decl, template_arg_ids,
  54. explicit_template_arg_storage,
  55. /*diagnose=*/false)) {
  56. continue;
  57. }
  58. explicit_template_args = &explicit_template_arg_storage;
  59. }
  60. auto* fn_decl = template_decl ? template_decl->getTemplatedDecl()
  61. : cast<clang::FunctionDecl>(decl);
  62. auto* method_decl = dyn_cast<clang::CXXMethodDecl>(fn_decl);
  63. if (method_decl && !method_decl->isStatic() &&
  64. !isa<clang::CXXConstructorDecl>(fn_decl)) {
  65. clang::QualType self_type;
  66. clang::Expr::Classification self_classification;
  67. if (self_arg) {
  68. self_type = self_arg->getType();
  69. self_classification = self_arg->Classify(sema.Context);
  70. }
  71. if (template_decl) {
  72. sema.AddMethodTemplateCandidate(
  73. template_decl, found_decl,
  74. cast<clang::CXXRecordDecl>(template_decl->getDeclContext()),
  75. explicit_template_args, self_type, self_classification, args,
  76. candidate_set, SuppressUserConversions, PartialOverloading);
  77. } else if (method_decl->isOverloadedOperator()) {
  78. sema.AddMemberOperatorCandidates(method_decl->getOverloadedOperator(),
  79. candidate_set.getLocation(), args,
  80. candidate_set);
  81. } else {
  82. sema.AddMethodCandidate(method_decl, found_decl,
  83. method_decl->getParent(), self_type,
  84. self_classification, args, candidate_set,
  85. SuppressUserConversions, PartialOverloading);
  86. }
  87. } else if (template_decl) {
  88. sema.AddTemplateOverloadCandidate(
  89. template_decl, found_decl, explicit_template_args, args,
  90. candidate_set, SuppressUserConversions, PartialOverloading);
  91. } else {
  92. sema.AddOverloadCandidate(fn_decl, found_decl, args, candidate_set,
  93. SuppressUserConversions, PartialOverloading);
  94. }
  95. }
  96. }
  97. auto CheckCppOverloadAccess(
  98. Context& context, SemIR::LocId loc_id, clang::DeclAccessPair overload,
  99. SemIR::KnownInstId<SemIR::FunctionDecl> overload_inst_id,
  100. SemIR::NameScopeId parent_scope_id) -> void {
  101. SemIR::AccessKind member_access_kind = MapCppAccess(overload);
  102. if (member_access_kind == SemIR::AccessKind::Public) {
  103. return;
  104. }
  105. auto function_id = context.insts().Get(overload_inst_id).function_id;
  106. auto& function = context.functions().Get(function_id);
  107. if (!parent_scope_id.has_value()) {
  108. parent_scope_id = function.parent_scope_id;
  109. }
  110. auto name_scope_const_id = context.constant_values().Get(
  111. context.name_scopes().Get(parent_scope_id).inst_id());
  112. SemIR::AccessKind allowed_access_kind =
  113. GetHighestAllowedAccess(context, loc_id, name_scope_const_id);
  114. CheckAccess(context, loc_id, SemIR::LocId(overload_inst_id), function.name_id,
  115. member_access_kind,
  116. /*is_parent_access=*/false,
  117. {.constant_id = name_scope_const_id,
  118. .highest_allowed_access = allowed_access_kind});
  119. }
  120. auto PerformCppOverloadResolution(
  121. Context& context, SemIR::LocId loc_id,
  122. SemIR::CppOverloadSetId overload_set_id,
  123. llvm::ArrayRef<SemIR::InstId> template_arg_ids, SemIR::InstId self_id,
  124. llvm::ArrayRef<SemIR::InstId> arg_ids) -> SemIR::InstId {
  125. // Register an annotation scope to flush any Clang diagnostics when we return.
  126. // This is important to ensure that Clang diagnostics are properly interleaved
  127. // with Carbon diagnostics.
  128. Diagnostics::AnnotationScope annotate_diagnostics(&context.emitter(),
  129. [](auto& /*builder*/) {});
  130. // Map Carbon call argument types to C++ types.
  131. clang::Expr* self_expr = nullptr;
  132. if (self_id.has_value()) {
  133. self_expr = InventClangArg(context, self_id);
  134. if (!self_expr) {
  135. return SemIR::ErrorInst::InstId;
  136. }
  137. }
  138. auto maybe_arg_exprs = InventClangArgs(context, arg_ids);
  139. if (!maybe_arg_exprs.has_value()) {
  140. return SemIR::ErrorInst::InstId;
  141. }
  142. auto& arg_exprs = *maybe_arg_exprs;
  143. const SemIR::CppOverloadSet& overload_set =
  144. context.cpp_overload_sets().Get(overload_set_id);
  145. clang::SourceLocation loc = GetCppLocation(context, loc_id);
  146. // Add candidate functions from the name lookup.
  147. clang::OverloadCandidateSet candidate_set(
  148. loc,
  149. overload_set.operator_rewrite_info.OriginalOperator
  150. ? clang::OverloadCandidateSet::CandidateSetKind::CSK_Operator
  151. : clang::OverloadCandidateSet::CandidateSetKind::CSK_Normal,
  152. overload_set.operator_rewrite_info);
  153. AddOverloadCandidates(context, candidate_set,
  154. overload_set.candidate_functions, template_arg_ids,
  155. self_expr, arg_exprs);
  156. // Find best viable function among the candidates.
  157. clang::Sema& sema = context.clang_sema();
  158. clang::OverloadCandidateSet::iterator best_viable_fn;
  159. clang::OverloadingResult overloading_result =
  160. candidate_set.BestViableFunction(sema, loc, best_viable_fn);
  161. switch (overloading_result) {
  162. case clang::OverloadingResult::OR_Success: {
  163. CARBON_CHECK(best_viable_fn->Function);
  164. CARBON_CHECK(!best_viable_fn->RewriteKind);
  165. SemIR::InstId result_id = ImportCppFunctionDecl(
  166. context, loc_id, best_viable_fn->Function,
  167. {.num_params = static_cast<int32_t>(arg_exprs.size())});
  168. if (result_id != SemIR::ErrorInst::InstId) {
  169. CheckCppOverloadAccess(
  170. context, loc_id, best_viable_fn->FoundDecl,
  171. context.insts().GetAsKnownInstId<SemIR::FunctionDecl>(result_id),
  172. overload_set.parent_scope_id);
  173. }
  174. return result_id;
  175. }
  176. case clang::OverloadingResult::OR_No_Viable_Function: {
  177. candidate_set.NoteCandidates(
  178. clang::PartialDiagnosticAt(
  179. loc, sema.PDiag(clang::diag::err_ovl_no_viable_function_in_call)
  180. << GetCppName(context, overload_set.name_id)),
  181. sema, clang::OCD_AllCandidates, arg_exprs);
  182. return SemIR::ErrorInst::InstId;
  183. }
  184. case clang::OverloadingResult::OR_Ambiguous: {
  185. candidate_set.NoteCandidates(
  186. clang::PartialDiagnosticAt(
  187. loc, sema.PDiag(clang::diag::err_ovl_ambiguous_call)
  188. << GetCppName(context, overload_set.name_id)),
  189. sema, clang::OCD_AmbiguousCandidates, arg_exprs);
  190. return SemIR::ErrorInst::InstId;
  191. }
  192. case clang::OverloadingResult::OR_Deleted: {
  193. sema.DiagnoseUseOfDeletedFunction(
  194. loc, clang::SourceRange(loc, loc),
  195. GetCppName(context, overload_set.name_id), candidate_set,
  196. best_viable_fn->Function, arg_exprs);
  197. return SemIR::ErrorInst::InstId;
  198. }
  199. }
  200. }
  201. } // namespace Carbon::Check