|
| 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 | + |
| 5 | +#include "toolchain/check/cpp_overload_resolution.h" |
| 6 | + |
| 7 | +#include "clang/Sema/Overload.h" |
| 8 | +#include "clang/Sema/Sema.h" |
| 9 | +#include "toolchain/check/cpp_type_mapping.h" |
| 10 | +#include "toolchain/check/import_cpp.h" |
| 11 | + |
| 12 | +namespace Carbon::Check { |
| 13 | + |
| 14 | +auto PerformCppOverloadResolution(Context& context, SemIR::LocId loc_id, |
| 15 | + SemIR::InstId callee_id, |
| 16 | + llvm::ArrayRef<SemIR::InstId> arg_ids) |
| 17 | + -> std::optional<SemIR::InstId> { |
| 18 | + Diagnostics::AnnotationScope annotate_diagnostics( |
| 19 | + &context.emitter(), [&](auto& builder) { |
| 20 | + CARBON_DIAGNOSTIC(InCallToCppFunction, Note, |
| 21 | + "in call to Cpp function here"); |
| 22 | + builder.Note(loc_id, InCallToCppFunction); |
| 23 | + }); |
| 24 | + |
| 25 | + // Map Carbon call argument types to C++ types. |
| 26 | + llvm::SmallVector<clang::Expr*> arg_exprs; |
| 27 | + arg_exprs.reserve(arg_ids.size()); |
| 28 | + for (SemIR::InstId arg_id : arg_ids) { |
| 29 | + clang::QualType arg_cpp_type = MapToCppType(context, arg_id); |
| 30 | + if (arg_cpp_type.isNull()) { |
| 31 | + CARBON_DIAGNOSTIC(CppCallArgTypeNotSupported, Error, |
| 32 | + "call argument of type {0} is not supported", |
| 33 | + TypeOfInstId); |
| 34 | + context.emitter().Emit(loc_id, CppCallArgTypeNotSupported, arg_id); |
| 35 | + return std::nullopt; |
| 36 | + } |
| 37 | + // TODO: Allocate these on the stack. |
| 38 | + arg_exprs.emplace_back(new (context.ast_context()) clang::OpaqueValueExpr( |
| 39 | + // TODO: Add location accordingly. |
| 40 | + clang::SourceLocation(), arg_cpp_type.getNonReferenceType(), |
| 41 | + clang::ExprValueKind::VK_LValue)); |
| 42 | + } |
| 43 | + |
| 44 | + auto overload_set_type = |
| 45 | + context.types() |
| 46 | + .GetAsInst(context.insts().Get(callee_id).type_id()) |
| 47 | + .TryAs<SemIR::CppOverloadSetType>(); |
| 48 | + // TODO: CHECK-fail or store CppOverloadSetId in the CalleeFunction and pass |
| 49 | + // it in here. |
| 50 | + if (!overload_set_type) { |
| 51 | + return std::nullopt; |
| 52 | + } |
| 53 | + const SemIR::CppOverloadSet& overload_set = |
| 54 | + context.cpp_overload_sets().Get(overload_set_type->overload_set_id); |
| 55 | + |
| 56 | + // Add candidate functions from the name lookup. |
| 57 | + clang::OverloadCandidateSet candidate_set( |
| 58 | + // TODO: Add location accordingly. |
| 59 | + clang::SourceLocation(), |
| 60 | + clang::OverloadCandidateSet::CandidateSetKind::CSK_Normal); |
| 61 | + |
| 62 | + clang::ASTUnit* ast = context.sem_ir().clang_ast_unit(); |
| 63 | + CARBON_CHECK(ast); |
| 64 | + clang::Sema& sema = ast->getSema(); |
| 65 | + |
| 66 | + // TODO: Add support for method calls. |
| 67 | + for (clang::NamedDecl* candidate : overload_set.candidate_functions) { |
| 68 | + if (auto* fn_decl = dyn_cast<clang::FunctionDecl>(candidate)) { |
| 69 | + sema.AddOverloadCandidate( |
| 70 | + fn_decl, clang::DeclAccessPair::make(fn_decl, candidate->getAccess()), |
| 71 | + arg_exprs, candidate_set); |
| 72 | + } else if (isa<clang::FunctionTemplateDecl>(candidate)) { |
| 73 | + CARBON_DIAGNOSTIC(CppTemplateFunctionNotSupported, Error, |
| 74 | + "template function is not supported"); |
| 75 | + context.emitter().Emit(loc_id, CppTemplateFunctionNotSupported); |
| 76 | + return std::nullopt; |
| 77 | + } |
| 78 | + // TODO: Diagnose if it's neither of these types. |
| 79 | + } |
| 80 | + |
| 81 | + // Find best viable function among the candidates. |
| 82 | + clang::OverloadCandidateSet::iterator best_viable_fn; |
| 83 | + clang::OverloadingResult overloading_result = |
| 84 | + // TODO: Add location accordingly. |
| 85 | + candidate_set.BestViableFunction(sema, clang::SourceLocation(), |
| 86 | + best_viable_fn); |
| 87 | + |
| 88 | + switch (overloading_result) { |
| 89 | + case clang::OverloadingResult::OR_Success: { |
| 90 | + // TODO: Handle the cases when Function is null. |
| 91 | + CARBON_CHECK(best_viable_fn->Function); |
| 92 | + SemIR::InstId result = |
| 93 | + ImportCppFunctionDecl(context, loc_id, best_viable_fn->Function); |
| 94 | + return result; |
| 95 | + } |
| 96 | + case clang::OverloadingResult::OR_No_Viable_Function: { |
| 97 | + // TODO: Add notes with the candidates. |
| 98 | + CARBON_DIAGNOSTIC(CppOverloadingNoViableFunctionFound, Error, |
| 99 | + "no matching function for call to `{0}`", |
| 100 | + SemIR::NameId); |
| 101 | + context.emitter().Emit(loc_id, CppOverloadingNoViableFunctionFound, |
| 102 | + overload_set.name_id); |
| 103 | + return std::nullopt; |
| 104 | + } |
| 105 | + case clang::OverloadingResult::OR_Ambiguous: { |
| 106 | + // TODO: Add notes with the candidates. |
| 107 | + CARBON_DIAGNOSTIC(CppOverloadingAmbiguousCandidatesFound, Error, |
| 108 | + "call to `{0}` is ambiguous", SemIR::NameId); |
| 109 | + context.emitter().Emit(loc_id, CppOverloadingAmbiguousCandidatesFound, |
| 110 | + overload_set.name_id); |
| 111 | + return std::nullopt; |
| 112 | + } |
| 113 | + case clang::OverloadingResult::OR_Deleted: { |
| 114 | + // TODO: Add notes with the candidates. |
| 115 | + CARBON_DIAGNOSTIC(CppOverloadingDeletedFunctionFound, Error, |
| 116 | + "call to deleted function `{0}`", SemIR::NameId); |
| 117 | + context.emitter().Emit(loc_id, CppOverloadingDeletedFunctionFound, |
| 118 | + overload_set.name_id); |
| 119 | + return std::nullopt; |
| 120 | + } |
| 121 | + } |
| 122 | +} |
| 123 | + |
| 124 | +} // namespace Carbon::Check |
0 commit comments