| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206 |
- // Part of the Carbon Language project, under the Apache License v2.0 with LLVM
- // Exceptions. See /LICENSE for license information.
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- #include "toolchain/check/cpp_overload_resolution.h"
- #include "clang/Sema/Overload.h"
- #include "clang/Sema/Sema.h"
- #include "toolchain/check/cpp_import.h"
- #include "toolchain/check/cpp_type_mapping.h"
- #include "toolchain/sem_ir/expr_info.h"
- #include "toolchain/sem_ir/typed_insts.h"
- namespace Carbon::Check {
- // Invents a Clang argument expression to use in overload resolution to
- // represent the given Carbon argument instruction.
- static auto InventClangArg(Context& context, SemIR::InstId arg_id)
- -> clang::Expr* {
- clang::ExprValueKind value_kind;
- switch (SemIR::GetExprCategory(context.sem_ir(), arg_id)) {
- case SemIR::ExprCategory::NotExpr:
- CARBON_FATAL("Should not see these here");
- case SemIR::ExprCategory::Error:
- return nullptr;
- case SemIR::ExprCategory::DurableRef:
- value_kind = clang::ExprValueKind::VK_LValue;
- break;
- case SemIR::ExprCategory::EphemeralRef:
- value_kind = clang::ExprValueKind::VK_XValue;
- break;
- case SemIR::ExprCategory::Value:
- case SemIR::ExprCategory::Initializing:
- value_kind = clang::ExprValueKind::VK_PRValue;
- break;
- case SemIR::ExprCategory::Mixed:
- // TODO: Handle this by creating an InitListExpr.
- value_kind = clang::ExprValueKind::VK_PRValue;
- break;
- }
- if (context.insts().Get(arg_id).type_id() == SemIR::ErrorInst::TypeId) {
- // The argument error has already been diagnosed.
- return nullptr;
- }
- clang::QualType arg_cpp_type = MapToCppType(context, arg_id);
- if (arg_cpp_type.isNull()) {
- CARBON_DIAGNOSTIC(CppCallArgTypeNotSupported, Error,
- "call argument of type {0} is not supported",
- TypeOfInstId);
- context.emitter().Emit(arg_id, CppCallArgTypeNotSupported, arg_id);
- return nullptr;
- }
- // TODO: Avoid heap allocating more of these on every call. Either cache them
- // somewhere or put them on the stack.
- return new (context.ast_context()) clang::OpaqueValueExpr(
- // TODO: Add location accordingly.
- clang::SourceLocation(), arg_cpp_type.getNonReferenceType(), value_kind);
- }
- // Adds the given overload candidates to the candidate set.
- static auto AddOverloadCandidataes(clang::Sema& sema,
- clang::OverloadCandidateSet& candidate_set,
- const clang::UnresolvedSetImpl& functions,
- clang::Expr* self_arg,
- llvm::ArrayRef<clang::Expr*> args) -> void {
- constexpr bool SuppressUserConversions = false;
- constexpr bool PartialOverloading = false;
- constexpr clang::TemplateArgumentListInfo* ExplicitTemplateArgs = nullptr;
- for (auto found_decl : functions.pairs()) {
- auto* decl = found_decl.getDecl()->getUnderlyingDecl();
- auto* template_decl = dyn_cast<clang::FunctionTemplateDecl>(decl);
- auto* fn_decl = template_decl ? template_decl->getTemplatedDecl()
- : cast<clang::FunctionDecl>(decl);
- auto* method_decl = dyn_cast<clang::CXXMethodDecl>(fn_decl);
- if (method_decl && !method_decl->isStatic() &&
- !isa<clang::CXXConstructorDecl>(fn_decl)) {
- clang::QualType self_type;
- clang::Expr::Classification self_classification;
- if (self_arg) {
- self_type = self_arg->getType();
- self_classification = self_arg->Classify(sema.Context);
- }
- if (template_decl) {
- sema.AddMethodTemplateCandidate(
- template_decl, found_decl,
- cast<clang::CXXRecordDecl>(template_decl->getDeclContext()),
- ExplicitTemplateArgs, self_type, self_classification, args,
- candidate_set, SuppressUserConversions, PartialOverloading);
- } else {
- sema.AddMethodCandidate(method_decl, found_decl,
- method_decl->getParent(), self_type,
- self_classification, args, candidate_set,
- SuppressUserConversions, PartialOverloading);
- }
- } else {
- if (template_decl) {
- sema.AddTemplateOverloadCandidate(
- template_decl, found_decl, ExplicitTemplateArgs, args,
- candidate_set, SuppressUserConversions, PartialOverloading);
- } else {
- sema.AddOverloadCandidate(fn_decl, found_decl, args, candidate_set,
- SuppressUserConversions, PartialOverloading);
- }
- }
- }
- }
- auto PerformCppOverloadResolution(Context& context, SemIR::LocId loc_id,
- SemIR::CppOverloadSetId overload_set_id,
- SemIR::InstId self_id,
- llvm::ArrayRef<SemIR::InstId> arg_ids)
- -> SemIR::InstId {
- Diagnostics::AnnotationScope annotate_diagnostics(
- &context.emitter(), [&](auto& builder) {
- CARBON_DIAGNOSTIC(InCallToCppFunction, Note,
- "in call to Cpp function here");
- builder.Note(loc_id, InCallToCppFunction);
- });
- // Map Carbon call argument types to C++ types.
- clang::Expr* self_expr = nullptr;
- if (self_id.has_value()) {
- self_expr = InventClangArg(context, self_id);
- if (!self_expr) {
- return SemIR::ErrorInst::InstId;
- }
- }
- llvm::SmallVector<clang::Expr*> arg_exprs;
- arg_exprs.reserve(arg_ids.size());
- for (SemIR::InstId arg_id : arg_ids) {
- auto* arg_expr = InventClangArg(context, arg_id);
- if (!arg_expr) {
- return SemIR::ErrorInst::InstId;
- }
- arg_exprs.push_back(arg_expr);
- }
- const SemIR::CppOverloadSet& overload_set =
- context.cpp_overload_sets().Get(overload_set_id);
- // Add candidate functions from the name lookup.
- clang::OverloadCandidateSet candidate_set(
- // TODO: Add location accordingly.
- clang::SourceLocation(),
- clang::OverloadCandidateSet::CandidateSetKind::CSK_Normal);
- clang::ASTUnit* ast = context.sem_ir().clang_ast_unit();
- CARBON_CHECK(ast);
- clang::Sema& sema = ast->getSema();
- AddOverloadCandidataes(sema, candidate_set, overload_set.candidate_functions,
- self_expr, arg_exprs);
- // Find best viable function among the candidates.
- clang::OverloadCandidateSet::iterator best_viable_fn;
- clang::OverloadingResult overloading_result =
- // TODO: Add location accordingly.
- candidate_set.BestViableFunction(sema, clang::SourceLocation(),
- best_viable_fn);
- switch (overloading_result) {
- case clang::OverloadingResult::OR_Success: {
- // TODO: Handle the cases when Function is null.
- CARBON_CHECK(best_viable_fn->Function);
- SemIR::InstId result =
- ImportCppFunctionDecl(context, loc_id, best_viable_fn->Function);
- return result;
- }
- case clang::OverloadingResult::OR_No_Viable_Function: {
- // TODO: Add notes with the candidates.
- CARBON_DIAGNOSTIC(CppOverloadingNoViableFunctionFound, Error,
- "no matching function for call to `{0}`",
- SemIR::NameId);
- context.emitter().Emit(loc_id, CppOverloadingNoViableFunctionFound,
- overload_set.name_id);
- return SemIR::ErrorInst::InstId;
- }
- case clang::OverloadingResult::OR_Ambiguous: {
- // TODO: Add notes with the candidates.
- CARBON_DIAGNOSTIC(CppOverloadingAmbiguousCandidatesFound, Error,
- "call to `{0}` is ambiguous", SemIR::NameId);
- context.emitter().Emit(loc_id, CppOverloadingAmbiguousCandidatesFound,
- overload_set.name_id);
- return SemIR::ErrorInst::InstId;
- }
- case clang::OverloadingResult::OR_Deleted: {
- // TODO: Add notes with the candidates.
- CARBON_DIAGNOSTIC(CppOverloadingDeletedFunctionFound, Error,
- "call to deleted function `{0}`", SemIR::NameId);
- context.emitter().Emit(loc_id, CppOverloadingDeletedFunctionFound,
- overload_set.name_id);
- return SemIR::ErrorInst::InstId;
- }
- }
- }
- } // namespace Carbon::Check
|