mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-06 06:54:44 +01:00
C++ interop: Support C++20 operator and overload resolution for expression rewriting (#6171)
This allows to find the spaceship `operator<=>` when a comparison operator is not available, and `operator==` when `operator!=` is not available. Support added to both lookup and overload resolution, by adding `OperatorRewriteInfo` and propagating it in `CppOverloadSet`. In case overload resolution chooses to use an operator which requires rewriting, we emit a `TODO` since rewriting is not yet supported. Part of #6170.
This commit is contained in:
@@ -2060,16 +2060,17 @@ static auto LookupBuiltinTypes(Context& context, SemIR::LocId loc_id,
|
||||
return inst_id;
|
||||
}
|
||||
|
||||
auto ImportCppOverloadSet(Context& context, SemIR::NameScopeId scope_id,
|
||||
SemIR::NameId name_id,
|
||||
clang::CXXRecordDecl* naming_class,
|
||||
clang::UnresolvedSet<4>&& overload_set)
|
||||
auto ImportCppOverloadSet(
|
||||
Context& context, SemIR::NameScopeId scope_id, SemIR::NameId name_id,
|
||||
clang::CXXRecordDecl* naming_class, clang::UnresolvedSet<4>&& overload_set,
|
||||
clang::OverloadCandidateSet::OperatorRewriteInfo operator_rewrite_info)
|
||||
-> SemIR::InstId {
|
||||
SemIR::CppOverloadSetId overload_set_id = context.cpp_overload_sets().Add(
|
||||
SemIR::CppOverloadSet{.name_id = name_id,
|
||||
.parent_scope_id = scope_id,
|
||||
.naming_class = naming_class,
|
||||
.candidate_functions = std::move(overload_set)});
|
||||
.candidate_functions = std::move(overload_set),
|
||||
.operator_rewrite_info = operator_rewrite_info});
|
||||
|
||||
auto overload_set_inst_id =
|
||||
// TODO: Add a location.
|
||||
@@ -2110,7 +2111,8 @@ static auto ImportOverloadSetIntoScope(Context& context,
|
||||
-> SemIR::ScopeLookupResult {
|
||||
SemIR::AccessKind access_kind = GetOverloadSetAccess(overload_set);
|
||||
SemIR::InstId inst_id = ImportCppOverloadSet(
|
||||
context, scope_id, name_id, naming_class, std::move(overload_set));
|
||||
context, scope_id, name_id, naming_class, std::move(overload_set),
|
||||
/*operator_rewrite_info=*/{});
|
||||
AddNameToScope(context, scope_id, name_id, access_kind, inst_id);
|
||||
return SemIR::ScopeLookupResult::MakeWrappedLookupResult(inst_id,
|
||||
access_kind);
|
||||
|
||||
@@ -32,10 +32,10 @@ auto ImportCppFunctionDecl(Context& context, SemIR::LocId loc_id,
|
||||
-> SemIR::InstId;
|
||||
|
||||
// Imports an overloaded function set from Clang to Carbon.
|
||||
auto ImportCppOverloadSet(Context& context, SemIR::NameScopeId scope_id,
|
||||
SemIR::NameId name_id,
|
||||
clang::CXXRecordDecl* naming_class,
|
||||
clang::UnresolvedSet<4>&& overload_set)
|
||||
auto ImportCppOverloadSet(
|
||||
Context& context, SemIR::NameScopeId scope_id, SemIR::NameId name_id,
|
||||
clang::CXXRecordDecl* naming_class, clang::UnresolvedSet<4>&& overload_set,
|
||||
clang::OverloadCandidateSet::OperatorRewriteInfo operator_rewrite_info)
|
||||
-> SemIR::InstId;
|
||||
|
||||
// Looks up the given name in the Clang AST generated when importing C++ code
|
||||
|
||||
@@ -190,10 +190,12 @@ auto LookupCppOperator(Context& context, SemIR::LocId loc_id, Operator op,
|
||||
return SemIR::ErrorInst::InstId;
|
||||
}
|
||||
|
||||
clang::SourceLocation loc = GetCppLocation(context, loc_id);
|
||||
clang::OverloadCandidateSet::OperatorRewriteInfo operator_rewrite_info(
|
||||
*op_kind, loc, /*AllowRewritten=*/true);
|
||||
clang::UnresolvedSet<4> functions;
|
||||
clang::OverloadCandidateSet candidate_set(
|
||||
GetCppLocation(context, loc_id),
|
||||
clang::OverloadCandidateSet::CSK_Operator);
|
||||
loc, clang::OverloadCandidateSet::CSK_Operator, operator_rewrite_info);
|
||||
// This works for both unary and binary operators.
|
||||
context.clang_sema().LookupOverloadedBinOp(candidate_set, *op_kind, functions,
|
||||
*arg_exprs);
|
||||
@@ -205,9 +207,9 @@ auto LookupCppOperator(Context& context, SemIR::LocId loc_id, Operator op,
|
||||
functions.addDecl(it.Function, it.FoundDecl.getAccess());
|
||||
}
|
||||
|
||||
return ImportCppOverloadSet(context, SemIR::NameScopeId::None,
|
||||
SemIR::NameId::CppOperator,
|
||||
/*naming_class=*/nullptr, std::move(functions));
|
||||
return ImportCppOverloadSet(
|
||||
context, SemIR::NameScopeId::None, SemIR::NameId::CppOperator,
|
||||
/*naming_class=*/nullptr, std::move(functions), operator_rewrite_info);
|
||||
}
|
||||
|
||||
auto IsCppOperatorMethodDecl(clang::Decl* decl) -> bool {
|
||||
|
||||
@@ -149,7 +149,11 @@ auto PerformCppOverloadResolution(Context& context, SemIR::LocId loc_id,
|
||||
|
||||
// Add candidate functions from the name lookup.
|
||||
clang::OverloadCandidateSet candidate_set(
|
||||
loc, clang::OverloadCandidateSet::CandidateSetKind::CSK_Normal);
|
||||
loc,
|
||||
overload_set.operator_rewrite_info.OriginalOperator
|
||||
? clang::OverloadCandidateSet::CandidateSetKind::CSK_Operator
|
||||
: clang::OverloadCandidateSet::CandidateSetKind::CSK_Normal,
|
||||
overload_set.operator_rewrite_info);
|
||||
|
||||
clang::Sema& sema = context.clang_sema();
|
||||
|
||||
@@ -165,6 +169,15 @@ auto PerformCppOverloadResolution(Context& context, SemIR::LocId loc_id,
|
||||
case clang::OverloadingResult::OR_Success: {
|
||||
// TODO: Handle the cases when Function is null.
|
||||
CARBON_CHECK(best_viable_fn->Function);
|
||||
if (best_viable_fn->RewriteKind) {
|
||||
context.TODO(
|
||||
loc_id,
|
||||
llvm::formatv("Rewriting operator{0} using {1} is not supported",
|
||||
clang::getOperatorSpelling(
|
||||
candidate_set.getRewriteInfo().OriginalOperator),
|
||||
best_viable_fn->Function->getNameAsString()));
|
||||
return SemIR::ErrorInst::InstId;
|
||||
}
|
||||
sema.MarkFunctionReferenced(loc, best_viable_fn->Function);
|
||||
SemIR::InstId result_id = ImportCppFunctionDecl(
|
||||
context, loc_id, best_viable_fn->Function,
|
||||
|
||||
Reference in New Issue
Block a user