overload_resolution.cpp 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  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/check/cpp/import.h"
  9. #include "toolchain/check/cpp/location.h"
  10. #include "toolchain/check/cpp/type_mapping.h"
  11. #include "toolchain/sem_ir/ids.h"
  12. #include "toolchain/sem_ir/typed_insts.h"
  13. namespace Carbon::Check {
  14. // Map a Carbon name into a C++ name.
  15. static auto GetCppName(Context& context, SemIR::NameId name_id)
  16. -> clang::DeclarationName {
  17. // TODO: Some special names should probably use different formatting. In
  18. // particular, NameId::CppOperator should probably map back to a
  19. // CXXOperatorName.
  20. auto name_str = context.names().GetFormatted(name_id);
  21. return clang::DeclarationName(&context.ast_context().Idents.get(name_str));
  22. }
  23. // Adds the given overload candidates to the candidate set.
  24. static auto AddOverloadCandidataes(clang::Sema& sema,
  25. clang::OverloadCandidateSet& candidate_set,
  26. const clang::UnresolvedSetImpl& functions,
  27. clang::Expr* self_arg,
  28. llvm::ArrayRef<clang::Expr*> args) -> void {
  29. constexpr bool SuppressUserConversions = false;
  30. constexpr bool PartialOverloading = false;
  31. constexpr clang::TemplateArgumentListInfo* ExplicitTemplateArgs = nullptr;
  32. for (auto found_decl : functions.pairs()) {
  33. auto* decl = found_decl.getDecl()->getUnderlyingDecl();
  34. auto* template_decl = dyn_cast<clang::FunctionTemplateDecl>(decl);
  35. auto* fn_decl = template_decl ? template_decl->getTemplatedDecl()
  36. : cast<clang::FunctionDecl>(decl);
  37. auto* method_decl = dyn_cast<clang::CXXMethodDecl>(fn_decl);
  38. if (method_decl && !method_decl->isStatic() &&
  39. !isa<clang::CXXConstructorDecl>(fn_decl)) {
  40. clang::QualType self_type;
  41. clang::Expr::Classification self_classification;
  42. if (self_arg) {
  43. self_type = self_arg->getType();
  44. self_classification = self_arg->Classify(sema.Context);
  45. }
  46. if (template_decl) {
  47. sema.AddMethodTemplateCandidate(
  48. template_decl, found_decl,
  49. cast<clang::CXXRecordDecl>(template_decl->getDeclContext()),
  50. ExplicitTemplateArgs, self_type, self_classification, args,
  51. candidate_set, SuppressUserConversions, PartialOverloading);
  52. } else {
  53. sema.AddMethodCandidate(method_decl, found_decl,
  54. method_decl->getParent(), self_type,
  55. self_classification, args, candidate_set,
  56. SuppressUserConversions, PartialOverloading);
  57. }
  58. } else {
  59. if (template_decl) {
  60. sema.AddTemplateOverloadCandidate(
  61. template_decl, found_decl, ExplicitTemplateArgs, args,
  62. candidate_set, SuppressUserConversions, PartialOverloading);
  63. } else {
  64. sema.AddOverloadCandidate(fn_decl, found_decl, args, candidate_set,
  65. SuppressUserConversions, PartialOverloading);
  66. }
  67. }
  68. }
  69. }
  70. auto PerformCppOverloadResolution(Context& context, SemIR::LocId loc_id,
  71. SemIR::CppOverloadSetId overload_set_id,
  72. SemIR::InstId self_id,
  73. llvm::ArrayRef<SemIR::InstId> arg_ids)
  74. -> SemIR::InstId {
  75. // Map Carbon call argument types to C++ types.
  76. clang::Expr* self_expr = nullptr;
  77. if (self_id.has_value()) {
  78. self_expr = InventClangArg(context, self_id);
  79. if (!self_expr) {
  80. return SemIR::ErrorInst::InstId;
  81. }
  82. }
  83. auto maybe_arg_exprs = InventClangArgs(context, arg_ids);
  84. if (!maybe_arg_exprs.has_value()) {
  85. return SemIR::ErrorInst::InstId;
  86. }
  87. auto& arg_exprs = *maybe_arg_exprs;
  88. const SemIR::CppOverloadSet& overload_set =
  89. context.cpp_overload_sets().Get(overload_set_id);
  90. clang::SourceLocation loc = GetCppLocation(context, loc_id);
  91. // Add candidate functions from the name lookup.
  92. clang::OverloadCandidateSet candidate_set(
  93. loc, clang::OverloadCandidateSet::CandidateSetKind::CSK_Normal);
  94. clang::ASTUnit* ast = context.sem_ir().clang_ast_unit();
  95. CARBON_CHECK(ast);
  96. clang::Sema& sema = ast->getSema();
  97. AddOverloadCandidataes(sema, candidate_set, overload_set.candidate_functions,
  98. self_expr, arg_exprs);
  99. // Find best viable function among the candidates.
  100. clang::OverloadCandidateSet::iterator best_viable_fn;
  101. clang::OverloadingResult overloading_result =
  102. candidate_set.BestViableFunction(sema, loc, best_viable_fn);
  103. switch (overloading_result) {
  104. case clang::OverloadingResult::OR_Success: {
  105. // TODO: Handle the cases when Function is null.
  106. CARBON_CHECK(best_viable_fn->Function);
  107. sema.MarkFunctionReferenced(loc, best_viable_fn->Function);
  108. SemIR::InstId result =
  109. ImportCppFunctionDecl(context, loc_id, best_viable_fn->Function);
  110. return result;
  111. }
  112. case clang::OverloadingResult::OR_No_Viable_Function: {
  113. candidate_set.NoteCandidates(
  114. clang::PartialDiagnosticAt(
  115. loc, sema.PDiag(clang::diag::err_ovl_no_viable_function_in_call)
  116. << GetCppName(context, overload_set.name_id)),
  117. sema, clang::OCD_AllCandidates, arg_exprs);
  118. return SemIR::ErrorInst::InstId;
  119. }
  120. case clang::OverloadingResult::OR_Ambiguous: {
  121. candidate_set.NoteCandidates(
  122. clang::PartialDiagnosticAt(
  123. loc, sema.PDiag(clang::diag::err_ovl_ambiguous_call)
  124. << GetCppName(context, overload_set.name_id)),
  125. sema, clang::OCD_AmbiguousCandidates, arg_exprs);
  126. return SemIR::ErrorInst::InstId;
  127. }
  128. case clang::OverloadingResult::OR_Deleted: {
  129. sema.DiagnoseUseOfDeletedFunction(
  130. loc, clang::SourceRange(loc, loc),
  131. GetCppName(context, overload_set.name_id), candidate_set,
  132. best_viable_fn->Function, arg_exprs);
  133. return SemIR::ErrorInst::InstId;
  134. }
  135. }
  136. }
  137. } // namespace Carbon::Check