mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-02 16:45:50 +01:00
Overload resolution for C++ operators (#6092)
Multiple overloads for the same operator are now resolved using overload resolution. This change doesn't try to solve all issues with operator lookup. Moved the operator lookup logic from `import` to `operators` and changed it to take the args into account. Use `Sema::LookupOverloadedBinOp()` (with ADL) when looking up operator functions to create an overload set. Verified all demos in #6017, #6020 and #6024 still work. C++ Interop Demo: ```c++ // my_number.h class MyNumber { public: explicit MyNumber(int value) : value_(value) {} auto value() const -> int { return value_; } private: int value_; }; class NotMyNumber {}; auto operator+(MyNumber lhs, MyNumber rhs) -> MyNumber; auto operator+(NotMyNumber lhs, NotMyNumber rhs) -> NotMyNumber; ``` ```c++ // my_number.cpp #include "my_number.h" auto operator+(MyNumber lhs, MyNumber rhs) -> MyNumber { return MyNumber(lhs.value() + rhs.value()); } auto operator+(NotMyNumber lhs, NotMyNumber /*rhs*/) -> NotMyNumber { return lhs; } ``` ```carbon // main.carbon library "Main"; import Core library "io"; import Cpp library "my_number.h"; fn Run() -> i32 { // Arithmetic var num1: Cpp.MyNumber = Cpp.MyNumber.MyNumber(14); var num2: Cpp.MyNumber = Cpp.MyNumber.MyNumber(5); Core.Print(num1.value()); Core.Print(num2.value()); Core.Print((num1 + num2).value()); return 0; } ``` **After this change:** ```shell $ clang -c my_number.cpp $ bazel-bin/toolchain/carbon compile main.carbon $ bazel-bin/toolchain/carbon link my_number.o main.o --output=demo $ ./demo 14 5 19 ``` **Before this change** ```shell $ bazel-bin/toolchain/carbon compile main.carbon main.carbon:14:15: error: semantics TODO: `Unsupported: Lookup succeeded but couldn't find a single result; LookupResultKind: 3` Core.Print((num1 + num2).value()); ^~~~~~~~~~~ main.carbon:14:15: note: in `Cpp` operator `AddWith` lookup Core.Print((num1 + num2).value()); ^~~~~~~~~~~ ``` Part of https://github.com/carbon-language/carbon-lang/issues/5995.
This commit is contained in:
@@ -8,63 +8,11 @@
|
||||
#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/ids.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,
|
||||
@@ -134,14 +82,9 @@ auto PerformCppOverloadResolution(Context& context, SemIR::LocId loc_id,
|
||||
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);
|
||||
auto arg_exprs = InventClangArgs(context, arg_ids);
|
||||
if (!arg_exprs.has_value()) {
|
||||
return SemIR::ErrorInst::InstId;
|
||||
}
|
||||
|
||||
const SemIR::CppOverloadSet& overload_set =
|
||||
@@ -158,7 +101,7 @@ auto PerformCppOverloadResolution(Context& context, SemIR::LocId loc_id,
|
||||
clang::Sema& sema = ast->getSema();
|
||||
|
||||
AddOverloadCandidataes(sema, candidate_set, overload_set.candidate_functions,
|
||||
self_expr, arg_exprs);
|
||||
self_expr, *arg_exprs);
|
||||
|
||||
// Find best viable function among the candidates.
|
||||
clang::OverloadCandidateSet::iterator best_viable_fn;
|
||||
|
||||
Reference in New Issue
Block a user