Skip to content

Commit 5705b94

Browse files
authored
Add PerformCallToCppFunction() which calls simplified version of PerformCppOverloadResolution() before calling PerformCallToFunction() (#6122)
Instead of calling `PerformCppOverloadResolution()` and use the complex return value to call `PerformCallToFunction()`, we call `PerformCallToCppFunction()` which will call both `PerformCppOverloadResolution()` and `PerformCallToFunction()`. Followup of #6112. Part of #5995.
1 parent 3b6d202 commit 5705b94

File tree

9 files changed

+135
-107
lines changed

9 files changed

+135
-107
lines changed

toolchain/check/BUILD

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ cc_library(
2121
"context.cpp",
2222
"control_flow.cpp",
2323
"convert.cpp",
24+
"cpp/call.cpp",
2425
"cpp/custom_type_mapping.cpp",
2526
"cpp/import.cpp",
2627
"cpp/location.cpp",
@@ -72,6 +73,7 @@ cc_library(
7273
"context.h",
7374
"control_flow.h",
7475
"convert.h",
76+
"cpp/call.h",
7577
"cpp/custom_type_mapping.h",
7678
"cpp/import.h",
7779
"cpp/location.h",

toolchain/check/call.cpp

Lines changed: 8 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
#include "toolchain/check/context.h"
1111
#include "toolchain/check/control_flow.h"
1212
#include "toolchain/check/convert.h"
13-
#include "toolchain/check/cpp/overload_resolution.h"
13+
#include "toolchain/check/cpp/call.h"
1414
#include "toolchain/check/cpp/thunk.h"
1515
#include "toolchain/check/deduce.h"
1616
#include "toolchain/check/facet_type.h"
@@ -201,11 +201,10 @@ static auto CheckCalleeFunctionReturnType(Context& context, SemIR::LocId loc_id,
201201
return CheckFunctionReturnType(context, loc_id, function, callee_specific_id);
202202
}
203203

204-
// Performs a call where the callee is a function.
205-
static auto PerformCallToFunction(Context& context, SemIR::LocId loc_id,
206-
SemIR::InstId callee_id,
207-
const SemIR::CalleeFunction& callee_function,
208-
llvm::ArrayRef<SemIR::InstId> arg_ids)
204+
auto PerformCallToFunction(Context& context, SemIR::LocId loc_id,
205+
SemIR::InstId callee_id,
206+
const SemIR::CalleeFunction& callee_function,
207+
llvm::ArrayRef<SemIR::InstId> arg_ids)
209208
-> SemIR::InstId {
210209
// If the callee is a generic function, determine the generic argument values
211210
// for the call.
@@ -337,17 +336,9 @@ auto PerformCall(Context& context, SemIR::LocId loc_id, SemIR::InstId callee_id,
337336
}
338337

339338
case CARBON_KIND(SemIR::CalleeCppOverloadSet overload): {
340-
CppOverloadResolutionResult overload_result =
341-
PerformCppOverloadResolution(context, loc_id,
342-
overload.cpp_overload_set_id,
343-
overload.self_id, arg_ids);
344-
if (overload_result.callee_id == SemIR::ErrorInst::InstId) {
345-
return SemIR::ErrorInst::InstId;
346-
}
347-
CARBON_CHECK(overload_result.callee_function);
348-
return PerformCallToFunction(context, loc_id, overload_result.callee_id,
349-
*overload_result.callee_function,
350-
overload_result.arg_ids);
339+
return PerformCallToCppFunction(context, loc_id,
340+
overload.cpp_overload_set_id,
341+
overload.self_id, arg_ids);
351342
}
352343
}
353344
}

toolchain/check/call.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,14 @@
1010

1111
namespace Carbon::Check {
1212

13+
// Checks and builds SemIR for a call to `callee_id` with arguments `args_id`,
14+
// where the callee is a function.
15+
auto PerformCallToFunction(Context& context, SemIR::LocId loc_id,
16+
SemIR::InstId callee_id,
17+
const SemIR::CalleeFunction& callee_function,
18+
llvm::ArrayRef<SemIR::InstId> arg_ids)
19+
-> SemIR::InstId;
20+
1321
// Checks and builds SemIR for a call to `callee_id` with arguments `args_id`.
1422
auto PerformCall(Context& context, SemIR::LocId loc_id, SemIR::InstId callee_id,
1523
llvm::ArrayRef<SemIR::InstId> arg_ids) -> SemIR::InstId;

toolchain/check/cpp/call.cpp

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
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/call.h"
6+
7+
#include "toolchain/base/kind_switch.h"
8+
#include "toolchain/check/call.h"
9+
#include "toolchain/check/cpp/operators.h"
10+
#include "toolchain/check/cpp/overload_resolution.h"
11+
#include "toolchain/sem_ir/function.h"
12+
#include "toolchain/sem_ir/ids.h"
13+
#include "toolchain/sem_ir/typed_insts.h"
14+
15+
namespace Carbon::Check {
16+
17+
// Returns whether the function is an imported C++ operator member function.
18+
static auto IsCppOperatorMethod(Context& context, SemIR::FunctionId function_id)
19+
-> bool {
20+
SemIR::ClangDeclId clang_decl_id =
21+
context.functions().Get(function_id).clang_decl_id;
22+
return clang_decl_id.has_value() &&
23+
IsCppOperatorMethodDecl(
24+
context.clang_decls().Get(clang_decl_id).key.decl);
25+
}
26+
27+
auto PerformCallToCppFunction(Context& context, SemIR::LocId loc_id,
28+
SemIR::CppOverloadSetId overload_set_id,
29+
SemIR::InstId self_id,
30+
llvm::ArrayRef<SemIR::InstId> arg_ids)
31+
-> SemIR::InstId {
32+
SemIR::InstId callee_id = PerformCppOverloadResolution(
33+
context, loc_id, overload_set_id, self_id, arg_ids);
34+
SemIR::Callee callee = GetCallee(context.sem_ir(), callee_id);
35+
CARBON_KIND_SWITCH(callee) {
36+
case CARBON_KIND(SemIR::CalleeError _): {
37+
return SemIR::ErrorInst::InstId;
38+
}
39+
case CARBON_KIND(SemIR::CalleeFunction fn): {
40+
CARBON_CHECK(!fn.self_id.has_value());
41+
if (self_id.has_value()) {
42+
// Preserve the `self` argument from the original callee.
43+
fn.self_id = self_id;
44+
} else if (IsCppOperatorMethod(context, fn.function_id)) {
45+
// Adjust `self` and args for C++ overloaded operator methods.
46+
fn.self_id = arg_ids.consume_front();
47+
}
48+
return PerformCallToFunction(context, loc_id, callee_id, fn, arg_ids);
49+
}
50+
case CARBON_KIND(SemIR::CalleeCppOverloadSet _): {
51+
CARBON_FATAL("overloads can't be recursive");
52+
}
53+
case CARBON_KIND(SemIR::CalleeNonFunction _): {
54+
CARBON_FATAL("overloads should produce functions");
55+
}
56+
}
57+
}
58+
59+
} // namespace Carbon::Check

toolchain/check/cpp/call.h

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
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+
#ifndef CARBON_TOOLCHAIN_CHECK_CPP_CALL_H_
6+
#define CARBON_TOOLCHAIN_CHECK_CPP_CALL_H_
7+
8+
#include "toolchain/check/context.h"
9+
#include "toolchain/sem_ir/ids.h"
10+
11+
namespace Carbon::Check {
12+
13+
// Checks and builds SemIR for a call to a C++ function in the given overload
14+
// set with self `self_id` and arguments `arg_ids`.
15+
//
16+
// Chooses the best viable C++ function by performing Clang overloading
17+
// resolution over the overload set.
18+
//
19+
// Preserves the given self, if set. If not set, and the function is a C++
20+
// member operator, self will be set to the first argument, which in turn will
21+
// be removed from the given args.
22+
//
23+
// A set with a single non-templated function goes through the same rules for
24+
// overloading resolution. This is to make sure that calls that have no viable
25+
// implicit conversion sequence are rejected even when an implicit conversion is
26+
// possible. Keeping the same behavior here for consistency and supporting
27+
// migrations so that the migrated callers from C++ remain valid.
28+
auto PerformCallToCppFunction(Context& context, SemIR::LocId loc_id,
29+
SemIR::CppOverloadSetId overload_set_id,
30+
SemIR::InstId self_id,
31+
llvm::ArrayRef<SemIR::InstId> arg_ids)
32+
-> SemIR::InstId;
33+
34+
} // namespace Carbon::Check
35+
36+
#endif // CARBON_TOOLCHAIN_CHECK_CPP_CALL_H_

toolchain/check/cpp/operators.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,4 +210,9 @@ auto LookupCppOperator(Context& context, SemIR::LocId loc_id, Operator op,
210210
/*naming_class=*/nullptr, std::move(functions));
211211
}
212212

213+
auto IsCppOperatorMethodDecl(clang::Decl* decl) -> bool {
214+
auto* clang_method_decl = dyn_cast<clang::CXXMethodDecl>(decl);
215+
return clang_method_decl && clang_method_decl->isOverloadedOperator();
216+
}
217+
213218
} // namespace Carbon::Check

toolchain/check/cpp/operators.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ namespace Carbon::Check {
1717
auto LookupCppOperator(Context& context, SemIR::LocId loc_id, Operator op,
1818
llvm::ArrayRef<SemIR::InstId> arg_ids) -> SemIR::InstId;
1919

20+
// Returns whether the decl is an operator member function.
21+
auto IsCppOperatorMethodDecl(clang::Decl* decl) -> bool;
22+
2023
} // namespace Carbon::Check
2124

2225
#endif // CARBON_TOOLCHAIN_CHECK_CPP_OPERATORS_H_

toolchain/check/cpp/overload_resolution.cpp

Lines changed: 6 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include "toolchain/base/kind_switch.h"
1111
#include "toolchain/check/cpp/import.h"
1212
#include "toolchain/check/cpp/location.h"
13+
#include "toolchain/check/cpp/operators.h"
1314
#include "toolchain/check/cpp/type_mapping.h"
1415
#include "toolchain/check/member_access.h"
1516
#include "toolchain/check/name_lookup.h"
@@ -116,18 +117,10 @@ static auto CheckOverloadAccess(Context& context, SemIR::LocId loc_id,
116117
.highest_allowed_access = allowed_access_kind});
117118
}
118119

119-
// Returns whether the decl is an operator member function.
120-
static auto IsOperatorMethodDecl(clang::Decl* decl) -> bool {
121-
auto* clang_method_decl = dyn_cast<clang::CXXMethodDecl>(decl);
122-
return clang_method_decl && clang_method_decl->isOverloadedOperator();
123-
}
124-
125-
// Resolve which function to call, or returns an error instruction if overload
126-
// resolution failed.
127-
static auto ResolveCalleeId(Context& context, SemIR::LocId loc_id,
128-
SemIR::CppOverloadSetId overload_set_id,
129-
SemIR::InstId self_id,
130-
llvm::ArrayRef<SemIR::InstId> arg_ids)
120+
auto PerformCppOverloadResolution(Context& context, SemIR::LocId loc_id,
121+
SemIR::CppOverloadSetId overload_set_id,
122+
SemIR::InstId self_id,
123+
llvm::ArrayRef<SemIR::InstId> arg_ids)
131124
-> SemIR::InstId {
132125
// Register an annotation scope to flush any Clang diagnostics when we return.
133126
// This is important to ensure that Clang diagnostics are properly interleaved
@@ -177,7 +170,7 @@ static auto ResolveCalleeId(Context& context, SemIR::LocId loc_id,
177170
context, loc_id, best_viable_fn->Function,
178171
// If this is an operator method, the first arg will be used as self.
179172
arg_exprs.size() -
180-
(IsOperatorMethodDecl(best_viable_fn->Function) ? 1 : 0));
173+
(IsCppOperatorMethodDecl(best_viable_fn->Function) ? 1 : 0));
181174
CheckOverloadAccess(context, loc_id, overload_set,
182175
best_viable_fn->FoundDecl, result_id);
183176
return result_id;
@@ -208,50 +201,4 @@ static auto ResolveCalleeId(Context& context, SemIR::LocId loc_id,
208201
}
209202
}
210203

211-
// Returns whether the function is an imported C++ operator member function.
212-
static auto IsCppOperatorMethod(Context& context, SemIR::FunctionId function_id)
213-
-> bool {
214-
SemIR::ClangDeclId clang_decl_id =
215-
context.functions().Get(function_id).clang_decl_id;
216-
return clang_decl_id.has_value() &&
217-
IsOperatorMethodDecl(
218-
context.clang_decls().Get(clang_decl_id).key.decl);
219-
}
220-
221-
auto PerformCppOverloadResolution(Context& context, SemIR::LocId loc_id,
222-
SemIR::CppOverloadSetId overload_set_id,
223-
SemIR::InstId self_id,
224-
llvm::ArrayRef<SemIR::InstId> arg_ids)
225-
-> CppOverloadResolutionResult {
226-
CppOverloadResolutionResult result = {
227-
.callee_id =
228-
ResolveCalleeId(context, loc_id, overload_set_id, self_id, arg_ids),
229-
.arg_ids = arg_ids};
230-
SemIR::Callee callee = GetCallee(context.sem_ir(), result.callee_id);
231-
CARBON_KIND_SWITCH(callee) {
232-
case CARBON_KIND(SemIR::CalleeError _): {
233-
result.callee_id = SemIR::ErrorInst::InstId;
234-
return result;
235-
}
236-
case CARBON_KIND(SemIR::CalleeFunction fn): {
237-
CARBON_CHECK(!fn.self_id.has_value());
238-
if (self_id.has_value()) {
239-
// Preserve the `self` argument from the original callee.
240-
fn.self_id = self_id;
241-
} else if (IsCppOperatorMethod(context, fn.function_id)) {
242-
// Adjust `self` and args for C++ overloaded operator methods.
243-
fn.self_id = result.arg_ids.consume_front();
244-
}
245-
result.callee_function = fn;
246-
return result;
247-
}
248-
case CARBON_KIND(SemIR::CalleeCppOverloadSet _): {
249-
CARBON_FATAL("overloads can't be recursive");
250-
}
251-
case CARBON_KIND(SemIR::CalleeNonFunction _): {
252-
CARBON_FATAL("overloads should produce functions");
253-
}
254-
}
255-
}
256-
257204
} // namespace Carbon::Check

toolchain/check/cpp/overload_resolution.h

Lines changed: 8 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -11,42 +11,19 @@
1111

1212
namespace Carbon::Check {
1313

14-
// The result of performing C++ overload resolution.
15-
struct CppOverloadResolutionResult {
16-
// The resolved callee id, or ErrorInst::InstId on error.
17-
SemIR::InstId callee_id;
18-
19-
// The resolved callee, which may be different from the result of
20-
// `GetCalleeFunction()` to preserve self or set it to be the first argument
21-
// for C++ member operators. Not set if overload resolution failed.
22-
std::optional<SemIR::CalleeFunction> callee_function;
23-
24-
// The arguments to pass to the callee, which may be different from the
25-
// original arguments if the callee is a C++ member operator.
26-
llvm::ArrayRef<SemIR::InstId> arg_ids;
27-
};
28-
29-
// Performs overloading resolution for a call to an overloaded C++ set. A set
30-
// with a single non-templated function goes through the same rules for
31-
// overloading resolution. Uses Clang to find the best viable function for the
32-
// call.
33-
//
34-
// The callee function preserves the given self, if set. If not set, and the
35-
// function is a a C++ member operator, self will be set to the first argument,
36-
// which in turn will be removed from the given args.
14+
// Resolves which function to call using Clang overloading resolution, or
15+
// returns an error instruction if overload resolution failed.
3716
//
38-
// Note on non-overloaded functions: In C++, a single non-templated function is
39-
// also treated as an overloaded set and goes through the overload resolution to
40-
// ensure that the function is viable for the call. This is to make sure that
41-
// calls that have no viable implicit conversion sequence are rejected even when
42-
// an implicit conversion is possible. Keeping the same behavior here for
43-
// consistency and supporting migrations so that the migrated callers from C++
44-
// remain valid.
17+
// A set with a single non-templated function goes through the same rules for
18+
// overloading resolution. This is to make sure that calls that have no viable
19+
// implicit conversion sequence are rejected even when an implicit conversion is
20+
// possible. Keeping the same behavior here for consistency and supporting
21+
// migrations so that the migrated callers from C++ remain valid.
4522
auto PerformCppOverloadResolution(Context& context, SemIR::LocId loc_id,
4623
SemIR::CppOverloadSetId overload_set_id,
4724
SemIR::InstId self_id,
4825
llvm::ArrayRef<SemIR::InstId> arg_ids)
49-
-> CppOverloadResolutionResult;
26+
-> SemIR::InstId;
5027

5128
} // namespace Carbon::Check
5229

0 commit comments

Comments
 (0)