Skip to content

Commit 7c13bdd

Browse files
authored
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.
1 parent c9bb6b1 commit 7c13bdd

File tree

7 files changed

+419
-17
lines changed

7 files changed

+419
-17
lines changed

toolchain/check/cpp/import.cpp

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2060,16 +2060,17 @@ static auto LookupBuiltinTypes(Context& context, SemIR::LocId loc_id,
20602060
return inst_id;
20612061
}
20622062

2063-
auto ImportCppOverloadSet(Context& context, SemIR::NameScopeId scope_id,
2064-
SemIR::NameId name_id,
2065-
clang::CXXRecordDecl* naming_class,
2066-
clang::UnresolvedSet<4>&& overload_set)
2063+
auto ImportCppOverloadSet(
2064+
Context& context, SemIR::NameScopeId scope_id, SemIR::NameId name_id,
2065+
clang::CXXRecordDecl* naming_class, clang::UnresolvedSet<4>&& overload_set,
2066+
clang::OverloadCandidateSet::OperatorRewriteInfo operator_rewrite_info)
20672067
-> SemIR::InstId {
20682068
SemIR::CppOverloadSetId overload_set_id = context.cpp_overload_sets().Add(
20692069
SemIR::CppOverloadSet{.name_id = name_id,
20702070
.parent_scope_id = scope_id,
20712071
.naming_class = naming_class,
2072-
.candidate_functions = std::move(overload_set)});
2072+
.candidate_functions = std::move(overload_set),
2073+
.operator_rewrite_info = operator_rewrite_info});
20732074

20742075
auto overload_set_inst_id =
20752076
// TODO: Add a location.
@@ -2110,7 +2111,8 @@ static auto ImportOverloadSetIntoScope(Context& context,
21102111
-> SemIR::ScopeLookupResult {
21112112
SemIR::AccessKind access_kind = GetOverloadSetAccess(overload_set);
21122113
SemIR::InstId inst_id = ImportCppOverloadSet(
2113-
context, scope_id, name_id, naming_class, std::move(overload_set));
2114+
context, scope_id, name_id, naming_class, std::move(overload_set),
2115+
/*operator_rewrite_info=*/{});
21142116
AddNameToScope(context, scope_id, name_id, access_kind, inst_id);
21152117
return SemIR::ScopeLookupResult::MakeWrappedLookupResult(inst_id,
21162118
access_kind);

toolchain/check/cpp/import.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,10 @@ auto ImportCppFunctionDecl(Context& context, SemIR::LocId loc_id,
3232
-> SemIR::InstId;
3333

3434
// Imports an overloaded function set from Clang to Carbon.
35-
auto ImportCppOverloadSet(Context& context, SemIR::NameScopeId scope_id,
36-
SemIR::NameId name_id,
37-
clang::CXXRecordDecl* naming_class,
38-
clang::UnresolvedSet<4>&& overload_set)
35+
auto ImportCppOverloadSet(
36+
Context& context, SemIR::NameScopeId scope_id, SemIR::NameId name_id,
37+
clang::CXXRecordDecl* naming_class, clang::UnresolvedSet<4>&& overload_set,
38+
clang::OverloadCandidateSet::OperatorRewriteInfo operator_rewrite_info)
3939
-> SemIR::InstId;
4040

4141
// Looks up the given name in the Clang AST generated when importing C++ code

toolchain/check/cpp/operators.cpp

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -190,10 +190,12 @@ auto LookupCppOperator(Context& context, SemIR::LocId loc_id, Operator op,
190190
return SemIR::ErrorInst::InstId;
191191
}
192192

193+
clang::SourceLocation loc = GetCppLocation(context, loc_id);
194+
clang::OverloadCandidateSet::OperatorRewriteInfo operator_rewrite_info(
195+
*op_kind, loc, /*AllowRewritten=*/true);
193196
clang::UnresolvedSet<4> functions;
194197
clang::OverloadCandidateSet candidate_set(
195-
GetCppLocation(context, loc_id),
196-
clang::OverloadCandidateSet::CSK_Operator);
198+
loc, clang::OverloadCandidateSet::CSK_Operator, operator_rewrite_info);
197199
// This works for both unary and binary operators.
198200
context.clang_sema().LookupOverloadedBinOp(candidate_set, *op_kind, functions,
199201
*arg_exprs);
@@ -205,9 +207,9 @@ auto LookupCppOperator(Context& context, SemIR::LocId loc_id, Operator op,
205207
functions.addDecl(it.Function, it.FoundDecl.getAccess());
206208
}
207209

208-
return ImportCppOverloadSet(context, SemIR::NameScopeId::None,
209-
SemIR::NameId::CppOperator,
210-
/*naming_class=*/nullptr, std::move(functions));
210+
return ImportCppOverloadSet(
211+
context, SemIR::NameScopeId::None, SemIR::NameId::CppOperator,
212+
/*naming_class=*/nullptr, std::move(functions), operator_rewrite_info);
211213
}
212214

213215
auto IsCppOperatorMethodDecl(clang::Decl* decl) -> bool {

toolchain/check/cpp/overload_resolution.cpp

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,11 @@ auto PerformCppOverloadResolution(Context& context, SemIR::LocId loc_id,
149149

150150
// Add candidate functions from the name lookup.
151151
clang::OverloadCandidateSet candidate_set(
152-
loc, clang::OverloadCandidateSet::CandidateSetKind::CSK_Normal);
152+
loc,
153+
overload_set.operator_rewrite_info.OriginalOperator
154+
? clang::OverloadCandidateSet::CandidateSetKind::CSK_Operator
155+
: clang::OverloadCandidateSet::CandidateSetKind::CSK_Normal,
156+
overload_set.operator_rewrite_info);
153157

154158
clang::Sema& sema = context.clang_sema();
155159

@@ -165,6 +169,15 @@ auto PerformCppOverloadResolution(Context& context, SemIR::LocId loc_id,
165169
case clang::OverloadingResult::OR_Success: {
166170
// TODO: Handle the cases when Function is null.
167171
CARBON_CHECK(best_viable_fn->Function);
172+
if (best_viable_fn->RewriteKind) {
173+
context.TODO(
174+
loc_id,
175+
llvm::formatv("Rewriting operator{0} using {1} is not supported",
176+
clang::getOperatorSpelling(
177+
candidate_set.getRewriteInfo().OriginalOperator),
178+
best_viable_fn->Function->getNameAsString()));
179+
return SemIR::ErrorInst::InstId;
180+
}
168181
sema.MarkFunctionReferenced(loc, best_viable_fn->Function);
169182
SemIR::InstId result_id = ImportCppFunctionDecl(
170183
context, loc_id, best_viable_fn->Function,

0 commit comments

Comments
 (0)