Skip to content

Commit a839493

Browse files
committed
Unify "needs thunk" logic.
Remove duplication between determining whether a parameter needs custom thunk mapping and whether a function needs a thunk. Now a function needs a thunk if any parameter or the return type does. This fixes some inconsistencies; previously: - We would not require a thunk when passing an `unsigned int`, but if we had a thunk we'd pass `unsigned int` indirectly. - We would always require a thunk for an enum parameter, even though we'd actually pass it directly if its underlying type is a 32- or 64-bit integer. - We would require a thunk for a nullable pointer, even though we arrange for all pointer types to have the same ABI in Carbon and C++, including nullable pointers / Optional(T*).
1 parent 4f07b40 commit a839493

File tree

7 files changed

+178
-226
lines changed

7 files changed

+178
-226
lines changed

toolchain/check/cpp/import.cpp

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1738,14 +1738,15 @@ static auto ImportFunctionDecl(Context& context, SemIR::LocId loc_id,
17381738
builder.Note(loc_id, InCppThunk);
17391739
});
17401740

1741-
clang::FunctionDecl* thunk_clang_decl =
1742-
BuildCppThunk(context, function_info);
1743-
if (thunk_clang_decl) {
1744-
SemIR::FunctionId thunk_function_id = *ImportFunction(
1745-
context, loc_id, thunk_clang_decl, thunk_clang_decl->getNumParams());
1746-
SemIR::InstId thunk_function_decl_id =
1747-
context.functions().Get(thunk_function_id).first_owning_decl_id;
1748-
function_info.SetHasCppThunk(thunk_function_decl_id);
1741+
if (clang::FunctionDecl* thunk_clang_decl =
1742+
BuildCppThunk(context, function_info)) {
1743+
if (auto thunk_function_id =
1744+
ImportFunction(context, loc_id, thunk_clang_decl,
1745+
thunk_clang_decl->getNumParams())) {
1746+
SemIR::InstId thunk_function_decl_id =
1747+
context.functions().Get(*thunk_function_id).first_owning_decl_id;
1748+
function_info.SetHasCppThunk(thunk_function_decl_id);
1749+
}
17491750
}
17501751
}
17511752

toolchain/check/cpp/thunk.cpp

Lines changed: 64 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -50,106 +50,30 @@ static auto GenerateThunkMangledName(
5050
return mangled_name_stream.TakeStr();
5151
}
5252

53-
// Returns true if a C++ thunk is required for the given type. A C++ thunk is
54-
// required for any type except for void, pointer types and signed 32-bit and
55-
// 64-bit integers.
56-
static auto IsThunkRequiredForType(Context& context, SemIR::TypeId type_id)
57-
-> bool {
58-
if (!type_id.has_value() || type_id == SemIR::ErrorInst::TypeId) {
59-
return false;
60-
}
61-
62-
type_id = context.types().GetUnqualifiedType(type_id);
63-
64-
switch (context.types().GetAsInst(type_id).kind()) {
65-
case SemIR::PointerType::Kind: {
66-
return false;
67-
}
68-
69-
case SemIR::ClassType::Kind: {
70-
if (!context.types().IsComplete(type_id)) {
71-
// Signed integers of 32 or 64 bits should be completed when imported.
72-
return true;
73-
}
74-
75-
auto int_info = context.types().TryGetIntTypeInfo(type_id);
76-
if (!int_info || !int_info->bit_width.has_value()) {
77-
return true;
78-
}
79-
80-
llvm::APInt bit_width = context.ints().Get(int_info->bit_width);
81-
return bit_width != 32 && bit_width != 64;
82-
}
83-
84-
default:
85-
return true;
86-
}
87-
}
88-
89-
auto IsCppThunkRequired(Context& context, const SemIR::Function& function)
90-
-> bool {
91-
if (!function.clang_decl_id.has_value()) {
92-
return false;
93-
}
94-
95-
// A thunk is required if any parameter or return type requires it. However,
96-
// we don't generate a thunk if any relevant type is erroneous.
97-
bool thunk_required = false;
98-
99-
const auto& decl_info = context.clang_decls().Get(function.clang_decl_id);
100-
const auto* decl = cast<clang::FunctionDecl>(decl_info.key.decl);
101-
if (decl_info.key.num_params !=
102-
static_cast<int>(decl->getNumNonObjectParams())) {
103-
// We require a thunk if the number of parameters we want isn't all of them.
104-
// This happens if default arguments are in use, or (eventually) when
105-
// calling a varargs function.
106-
thunk_required = true;
107-
} else {
108-
// We require a thunk if any parameter is of reference type, even if the
109-
// corresponding SemIR function has an acceptable parameter type.
110-
// TODO: We should be able to avoid thunks for reference parameters.
111-
for (auto* param : decl->parameters()) {
112-
if (param->getType()->isReferenceType()) {
113-
thunk_required = true;
114-
break;
115-
}
116-
}
53+
// Returns whether the Carbon lowering for a parameter or return of this type is
54+
// known to match the C++ lowering.
55+
static auto IsSimpleAbiType(clang::ASTContext& ast_context,
56+
clang::QualType type, bool for_parameter) -> bool {
57+
if (type->isVoidType() || type->isPointerType()) {
58+
return true;
11759
}
11860

119-
SemIR::TypeId return_type_id =
120-
function.GetDeclaredReturnType(context.sem_ir());
121-
if (return_type_id.has_value()) {
122-
if (return_type_id == SemIR::ErrorInst::TypeId) {
123-
return false;
124-
}
125-
thunk_required =
126-
thunk_required || IsThunkRequiredForType(context, return_type_id);
61+
if (!for_parameter && type->isLValueReferenceType()) {
62+
// An lvalue reference return type maps to a pointer, which uses the same
63+
// lowering rule.
64+
return true;
12765
}
12866

129-
for (auto param_id :
130-
context.inst_blocks().GetOrEmpty(function.call_params_id)) {
131-
if (param_id == SemIR::ErrorInst::InstId) {
67+
if (const auto* enum_decl = type->getAsEnumDecl()) {
68+
// An enum type has a simple ABI if its underlying type does.
69+
type = enum_decl->getIntegerType();
70+
if (type.isNull()) {
13271
return false;
13372
}
134-
thunk_required =
135-
thunk_required ||
136-
IsThunkRequiredForType(
137-
context, context.insts().GetAs<SemIR::AnyParam>(param_id).type_id);
138-
}
139-
140-
return thunk_required;
141-
}
142-
143-
// Returns whether the type is void, a pointer, or a signed int of 32 or 64
144-
// bits.
145-
static auto IsSimpleAbiType(clang::ASTContext& ast_context,
146-
clang::QualType type) -> bool {
147-
if (type->isVoidType() || type->isPointerType()) {
148-
return true;
14973
}
15074

15175
if (const auto* builtin_type = type->getAs<clang::BuiltinType>()) {
152-
if (builtin_type->isSignedInteger()) {
76+
if (builtin_type->isIntegerType()) {
15377
uint64_t type_size = ast_context.getIntWidth(type);
15478
return type_size == 32 || type_size == 64;
15579
}
@@ -174,8 +98,8 @@ struct CalleeFunctionInfo {
17498
effective_return_type =
17599
is_ctor ? ast_context.getCanonicalTagType(method_decl->getParent())
176100
: decl->getReturnType();
177-
has_simple_return_type =
178-
IsSimpleAbiType(ast_context, effective_return_type);
101+
has_simple_return_type = IsSimpleAbiType(ast_context, effective_return_type,
102+
/*for_parameter=*/false);
179103
}
180104

181105
// Returns whether this callee has an implicit `this` parameter.
@@ -234,6 +158,52 @@ struct CalleeFunctionInfo {
234158
};
235159
} // namespace
236160

161+
auto IsCppThunkRequired(Context& context, const SemIR::Function& function)
162+
-> bool {
163+
if (!function.clang_decl_id.has_value()) {
164+
return false;
165+
}
166+
167+
const auto& decl_info = context.clang_decls().Get(function.clang_decl_id);
168+
auto* decl = cast<clang::FunctionDecl>(decl_info.key.decl);
169+
if (decl_info.key.num_params !=
170+
static_cast<int>(decl->getNumNonObjectParams())) {
171+
// We require a thunk if the number of parameters we want isn't all of them.
172+
// This happens if default arguments are in use, or (eventually) when
173+
// calling a varargs function.
174+
return true;
175+
}
176+
177+
CalleeFunctionInfo callee_info(decl, decl_info.key.num_params);
178+
if (!callee_info.has_simple_return_type) {
179+
return true;
180+
}
181+
182+
auto& ast_context = context.ast_context();
183+
if (callee_info.has_implicit_object_parameter()) {
184+
// TODO: The object parameter is a reference parameter, but we don't force a
185+
// thunk here like we do for explicit reference parameters in the case where
186+
// we would map the parameter to an `addr` parameter. We should make this
187+
// behavior consistent.
188+
auto* method_decl = cast<clang::CXXMethodDecl>(decl);
189+
if (method_decl->getRefQualifier() == clang::RQ_RValue ||
190+
method_decl->getMethodQualifiers().hasConst()) {
191+
return true;
192+
}
193+
}
194+
195+
const auto* function_type =
196+
decl->getType()->castAs<clang::FunctionProtoType>();
197+
for (int i : llvm::seq(decl->getNumParams())) {
198+
if (!IsSimpleAbiType(ast_context, function_type->getParamType(i),
199+
/*for_parameter=*/true)) {
200+
return true;
201+
}
202+
}
203+
204+
return false;
205+
}
206+
237207
// Given a pointer type, returns the corresponding _Nonnull-qualified pointer
238208
// type.
239209
static auto GetNonnullType(clang::ASTContext& ast_context,
@@ -255,7 +225,7 @@ static auto GetNonNullablePointerType(clang::ASTContext& ast_context,
255225
static auto GetThunkParameterType(clang::ASTContext& ast_context,
256226
clang::QualType callee_type)
257227
-> clang::QualType {
258-
if (IsSimpleAbiType(ast_context, callee_type)) {
228+
if (IsSimpleAbiType(ast_context, callee_type, /*for_parameter=*/true)) {
259229
return callee_type;
260230
}
261231
return GetNonNullablePointerType(ast_context, callee_type);

toolchain/check/testdata/interop/cpp/enum/anonymous.carbon

Lines changed: 13 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,8 @@ fn G() {
4747
// CHECK:STDOUT: %F.cpp_overload_set.value: %F.cpp_overload_set.type = cpp_overload_set_value @F.cpp_overload_set [concrete]
4848
// CHECK:STDOUT: %.4f0: type = class_type @.1 [concrete]
4949
// CHECK:STDOUT: %int_1.81a: %.4f0 = int_value 1 [concrete]
50-
// CHECK:STDOUT: %ptr.793: type = ptr_type %.4f0 [concrete]
51-
// CHECK:STDOUT: %F__carbon_thunk.type.eda1ac.1: type = fn_type @F__carbon_thunk.1 [concrete]
52-
// CHECK:STDOUT: %F__carbon_thunk.0cd6a8.1: %F__carbon_thunk.type.eda1ac.1 = struct_value () [concrete]
50+
// CHECK:STDOUT: %F.type: type = fn_type @F [concrete]
51+
// CHECK:STDOUT: %F: %F.type = struct_value () [concrete]
5352
// CHECK:STDOUT: %C: type = class_type @C [concrete]
5453
// CHECK:STDOUT: %C.C.cpp_overload_set.type: type = cpp_overload_set_type @C.C.cpp_overload_set [concrete]
5554
// CHECK:STDOUT: %C.C.cpp_overload_set.value: %C.C.cpp_overload_set.type = cpp_overload_set_value @C.C.cpp_overload_set [concrete]
@@ -60,19 +59,12 @@ fn G() {
6059
// CHECK:STDOUT: %C.F.cpp_overload_set.value: %C.F.cpp_overload_set.type = cpp_overload_set_value @C.F.cpp_overload_set [concrete]
6160
// CHECK:STDOUT: %.bb7: type = class_type @.2 [concrete]
6261
// CHECK:STDOUT: %int_1.1d6: %.bb7 = int_value 1 [concrete]
63-
// CHECK:STDOUT: %ptr.73d: type = ptr_type %.bb7 [concrete]
64-
// CHECK:STDOUT: %F__carbon_thunk.type.eda1ac.2: type = fn_type @F__carbon_thunk.2 [concrete]
65-
// CHECK:STDOUT: %F__carbon_thunk.0cd6a8.2: %F__carbon_thunk.type.eda1ac.2 = struct_value () [concrete]
62+
// CHECK:STDOUT: %C.F.type: type = fn_type @C.F [concrete]
63+
// CHECK:STDOUT: %C.F: %C.F.type = struct_value () [concrete]
6664
// CHECK:STDOUT: %type_where: type = facet_type <type where .Self impls <CanDestroy>> [concrete]
67-
// CHECK:STDOUT: %facet_value.597: %type_where = facet_value %.bb7, () [concrete]
68-
// CHECK:STDOUT: %DestroyT.binding.as_type.as.Destroy.impl.Op.type.52d: type = fn_type @DestroyT.binding.as_type.as.Destroy.impl.Op, @DestroyT.binding.as_type.as.Destroy.impl(%facet_value.597) [concrete]
69-
// CHECK:STDOUT: %DestroyT.binding.as_type.as.Destroy.impl.Op.afc: %DestroyT.binding.as_type.as.Destroy.impl.Op.type.52d = struct_value () [concrete]
70-
// CHECK:STDOUT: %facet_value.b21: %type_where = facet_value %C, () [concrete]
71-
// CHECK:STDOUT: %DestroyT.binding.as_type.as.Destroy.impl.Op.type.b92: type = fn_type @DestroyT.binding.as_type.as.Destroy.impl.Op, @DestroyT.binding.as_type.as.Destroy.impl(%facet_value.b21) [concrete]
65+
// CHECK:STDOUT: %facet_value: %type_where = facet_value %C, () [concrete]
66+
// CHECK:STDOUT: %DestroyT.binding.as_type.as.Destroy.impl.Op.type.b92: type = fn_type @DestroyT.binding.as_type.as.Destroy.impl.Op, @DestroyT.binding.as_type.as.Destroy.impl(%facet_value) [concrete]
7267
// CHECK:STDOUT: %DestroyT.binding.as_type.as.Destroy.impl.Op.841: %DestroyT.binding.as_type.as.Destroy.impl.Op.type.b92 = struct_value () [concrete]
73-
// CHECK:STDOUT: %facet_value.21d: %type_where = facet_value %.4f0, () [concrete]
74-
// CHECK:STDOUT: %DestroyT.binding.as_type.as.Destroy.impl.Op.type.02d: type = fn_type @DestroyT.binding.as_type.as.Destroy.impl.Op, @DestroyT.binding.as_type.as.Destroy.impl(%facet_value.21d) [concrete]
75-
// CHECK:STDOUT: %DestroyT.binding.as_type.as.Destroy.impl.Op.246: %DestroyT.binding.as_type.as.Destroy.impl.Op.type.02d = struct_value () [concrete]
7668
// CHECK:STDOUT: }
7769
// CHECK:STDOUT:
7870
// CHECK:STDOUT: imports {
@@ -84,7 +76,7 @@ fn G() {
8476
// CHECK:STDOUT: }
8577
// CHECK:STDOUT: %F.cpp_overload_set.value: %F.cpp_overload_set.type = cpp_overload_set_value @F.cpp_overload_set [concrete = constants.%F.cpp_overload_set.value]
8678
// CHECK:STDOUT: %int_1.81a: %.4f0 = int_value 1 [concrete = constants.%int_1.81a]
87-
// CHECK:STDOUT: %F__carbon_thunk.decl.e1b8ec.1: %F__carbon_thunk.type.eda1ac.1 = fn_decl @F__carbon_thunk.1 [concrete = constants.%F__carbon_thunk.0cd6a8.1] {
79+
// CHECK:STDOUT: %F.decl: %F.type = fn_decl @F [concrete = constants.%F] {
8880
// CHECK:STDOUT: <elided>
8981
// CHECK:STDOUT: } {
9082
// CHECK:STDOUT: <elided>
@@ -98,7 +90,7 @@ fn G() {
9890
// CHECK:STDOUT: }
9991
// CHECK:STDOUT: %C.F.cpp_overload_set.value: %C.F.cpp_overload_set.type = cpp_overload_set_value @C.F.cpp_overload_set [concrete = constants.%C.F.cpp_overload_set.value]
10092
// CHECK:STDOUT: %int_1.1d6: %.bb7 = int_value 1 [concrete = constants.%int_1.1d6]
101-
// CHECK:STDOUT: %F__carbon_thunk.decl.e1b8ec.2: %F__carbon_thunk.type.eda1ac.2 = fn_decl @F__carbon_thunk.2 [concrete = constants.%F__carbon_thunk.0cd6a8.2] {
93+
// CHECK:STDOUT: %C.F.decl: %C.F.type = fn_decl @C.F [concrete = constants.%C.F] {
10294
// CHECK:STDOUT: <elided>
10395
// CHECK:STDOUT: } {
10496
// CHECK:STDOUT: <elided>
@@ -115,10 +107,7 @@ fn G() {
115107
// CHECK:STDOUT: %F.ref.loc8: %F.cpp_overload_set.type = name_ref F, imports.%F.cpp_overload_set.value [concrete = constants.%F.cpp_overload_set.value]
116108
// CHECK:STDOUT: %Cpp.ref.loc8_9: <namespace> = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp]
117109
// CHECK:STDOUT: %b.ref: %.4f0 = name_ref b, imports.%int_1.81a [concrete = constants.%int_1.81a]
118-
// CHECK:STDOUT: %.loc8_12.1: ref %.4f0 = temporary_storage
119-
// CHECK:STDOUT: %.loc8_12.2: ref %.4f0 = temporary %.loc8_12.1, %b.ref
120-
// CHECK:STDOUT: %addr.loc8_14: %ptr.793 = addr_of %.loc8_12.2
121-
// CHECK:STDOUT: %F__carbon_thunk.call.loc8: init %empty_tuple.type = call imports.%F__carbon_thunk.decl.e1b8ec.1(%addr.loc8_14)
110+
// CHECK:STDOUT: %F.call: init %empty_tuple.type = call imports.%F.decl(%b.ref)
122111
// CHECK:STDOUT: %Cpp.ref.loc10_3: <namespace> = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp]
123112
// CHECK:STDOUT: %C.ref.loc10_6: type = name_ref C, imports.%C.decl [concrete = constants.%C]
124113
// CHECK:STDOUT: %C.ref.loc10_8: %C.C.cpp_overload_set.type = name_ref C, imports.%C.C.cpp_overload_set.value [concrete = constants.%C.C.cpp_overload_set.value]
@@ -133,25 +122,12 @@ fn G() {
133122
// CHECK:STDOUT: %C.ref.loc10_18: type = name_ref C, imports.%C.decl [concrete = constants.%C]
134123
// CHECK:STDOUT: %e.ref: %.bb7 = name_ref e, imports.%int_1.1d6 [concrete = constants.%int_1.1d6]
135124
// CHECK:STDOUT: %addr.loc10_11.2: %ptr.d9e = addr_of %.loc10_11.3
136-
// CHECK:STDOUT: %.loc10_20.1: ref %.bb7 = temporary_storage
137-
// CHECK:STDOUT: %.loc10_20.2: ref %.bb7 = temporary %.loc10_20.1, %e.ref
138-
// CHECK:STDOUT: %addr.loc10_22: %ptr.73d = addr_of %.loc10_20.2
139-
// CHECK:STDOUT: %F__carbon_thunk.call.loc10: init %empty_tuple.type = call imports.%F__carbon_thunk.decl.e1b8ec.2(%addr.loc10_11.2, %addr.loc10_22)
140-
// CHECK:STDOUT: %DestroyT.binding.as_type.as.Destroy.impl.Op.bound.loc10_20: <bound method> = bound_method %.loc10_20.2, constants.%DestroyT.binding.as_type.as.Destroy.impl.Op.afc
125+
// CHECK:STDOUT: %C.F.call: init %empty_tuple.type = call imports.%C.F.decl(%addr.loc10_11.2, %e.ref)
126+
// CHECK:STDOUT: %DestroyT.binding.as_type.as.Destroy.impl.Op.bound: <bound method> = bound_method %.loc10_11.3, constants.%DestroyT.binding.as_type.as.Destroy.impl.Op.841
141127
// CHECK:STDOUT: <elided>
142-
// CHECK:STDOUT: %bound_method.loc10_20: <bound method> = bound_method %.loc10_20.2, %DestroyT.binding.as_type.as.Destroy.impl.Op.specific_fn.1
143-
// CHECK:STDOUT: %addr.loc10_20: %ptr.73d = addr_of %.loc10_20.2
144-
// CHECK:STDOUT: %DestroyT.binding.as_type.as.Destroy.impl.Op.call.loc10_20: init %empty_tuple.type = call %bound_method.loc10_20(%addr.loc10_20)
145-
// CHECK:STDOUT: %DestroyT.binding.as_type.as.Destroy.impl.Op.bound.loc10_11: <bound method> = bound_method %.loc10_11.3, constants.%DestroyT.binding.as_type.as.Destroy.impl.Op.841
146-
// CHECK:STDOUT: <elided>
147-
// CHECK:STDOUT: %bound_method.loc10_11: <bound method> = bound_method %.loc10_11.3, %DestroyT.binding.as_type.as.Destroy.impl.Op.specific_fn.2
128+
// CHECK:STDOUT: %bound_method.loc10_11: <bound method> = bound_method %.loc10_11.3, %DestroyT.binding.as_type.as.Destroy.impl.Op.specific_fn
148129
// CHECK:STDOUT: %addr.loc10_11.3: %ptr.d9e = addr_of %.loc10_11.3
149-
// CHECK:STDOUT: %DestroyT.binding.as_type.as.Destroy.impl.Op.call.loc10_11: init %empty_tuple.type = call %bound_method.loc10_11(%addr.loc10_11.3)
150-
// CHECK:STDOUT: %DestroyT.binding.as_type.as.Destroy.impl.Op.bound.loc8: <bound method> = bound_method %.loc8_12.2, constants.%DestroyT.binding.as_type.as.Destroy.impl.Op.246
151-
// CHECK:STDOUT: <elided>
152-
// CHECK:STDOUT: %bound_method.loc8: <bound method> = bound_method %.loc8_12.2, %DestroyT.binding.as_type.as.Destroy.impl.Op.specific_fn.3
153-
// CHECK:STDOUT: %addr.loc8_12: %ptr.793 = addr_of %.loc8_12.2
154-
// CHECK:STDOUT: %DestroyT.binding.as_type.as.Destroy.impl.Op.call.loc8: init %empty_tuple.type = call %bound_method.loc8(%addr.loc8_12)
130+
// CHECK:STDOUT: %DestroyT.binding.as_type.as.Destroy.impl.Op.call: init %empty_tuple.type = call %bound_method.loc10_11(%addr.loc10_11.3)
155131
// CHECK:STDOUT: return
156132
// CHECK:STDOUT: }
157133
// CHECK:STDOUT:

toolchain/check/testdata/interop/cpp/function/decayed_param.carbon

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -117,8 +117,8 @@ fn F() {
117117
// CHECK:STDOUT: %OptionalStorage.impl_witness.01b: <witness> = impl_witness imports.%OptionalStorage.impl_witness_table.377, @ptr.as.OptionalStorage.impl(%i32) [concrete]
118118
// CHECK:STDOUT: %OptionalStorage.facet: %OptionalStorage.type = facet_value %ptr.235, (%OptionalStorage.impl_witness.01b) [concrete]
119119
// CHECK:STDOUT: %Optional.8fd: type = class_type @Optional, @Optional(%OptionalStorage.facet) [concrete]
120-
// CHECK:STDOUT: %TakesArray__carbon_thunk.type: type = fn_type @TakesArray__carbon_thunk [concrete]
121-
// CHECK:STDOUT: %TakesArray__carbon_thunk: %TakesArray__carbon_thunk.type = struct_value () [concrete]
120+
// CHECK:STDOUT: %TakesArray.type: type = fn_type @TakesArray [concrete]
121+
// CHECK:STDOUT: %TakesArray: %TakesArray.type = struct_value () [concrete]
122122
// CHECK:STDOUT: %ImplicitAs.type.6cc: type = facet_type <@ImplicitAs, @ImplicitAs(%Optional.8fd)> [concrete]
123123
// CHECK:STDOUT: %ImplicitAs.Convert.type.770: type = fn_type @ImplicitAs.Convert, @ImplicitAs(%Optional.8fd) [concrete]
124124
// CHECK:STDOUT: %T.binding.as_type.as.ImplicitAs.impl.Convert.type.6f7: type = fn_type @T.binding.as_type.as.ImplicitAs.impl.Convert.2, @T.binding.as_type.as.ImplicitAs.impl.3a5(%T.76d) [symbolic]
@@ -153,7 +153,7 @@ fn F() {
153153
// CHECK:STDOUT: %Core.import_ref.6db = import_ref Core//prelude/types/optional, loc{{\d+_\d+}}, unloaded
154154
// CHECK:STDOUT: %Core.import_ref.5a7 = import_ref Core//prelude/types/optional, loc{{\d+_\d+}}, unloaded
155155
// CHECK:STDOUT: %OptionalStorage.impl_witness_table.377 = impl_witness_table (%Core.import_ref.8c0, %Core.import_ref.566, %Core.import_ref.637, %Core.import_ref.6db, %Core.import_ref.5a7), @ptr.as.OptionalStorage.impl [concrete]
156-
// CHECK:STDOUT: %TakesArray__carbon_thunk.decl: %TakesArray__carbon_thunk.type = fn_decl @TakesArray__carbon_thunk [concrete = constants.%TakesArray__carbon_thunk] {
156+
// CHECK:STDOUT: %TakesArray.decl: %TakesArray.type = fn_decl @TakesArray [concrete = constants.%TakesArray] {
157157
// CHECK:STDOUT: <elided>
158158
// CHECK:STDOUT: } {
159159
// CHECK:STDOUT: <elided>
@@ -207,7 +207,7 @@ fn F() {
207207
// CHECK:STDOUT: %.loc11_18.2: init %Optional.8fd = converted %addr.loc11_18.1, %T.binding.as_type.as.ImplicitAs.impl.Convert.call
208208
// CHECK:STDOUT: %.loc11_18.3: ref %Optional.8fd = temporary %.loc11_18.1, %.loc11_18.2
209209
// CHECK:STDOUT: %.loc11_18.4: %Optional.8fd = bind_value %.loc11_18.3
210-
// CHECK:STDOUT: %TakesArray__carbon_thunk.call: init %empty_tuple.type = call imports.%TakesArray__carbon_thunk.decl(%.loc11_18.4)
210+
// CHECK:STDOUT: %TakesArray.call: init %empty_tuple.type = call imports.%TakesArray.decl(%.loc11_18.4)
211211
// CHECK:STDOUT: %DestroyT.binding.as_type.as.Destroy.impl.Op.bound.loc11: <bound method> = bound_method %.loc11_18.3, constants.%DestroyT.binding.as_type.as.Destroy.impl.Op.af3
212212
// CHECK:STDOUT: <elided>
213213
// CHECK:STDOUT: %bound_method.loc11_18.3: <bound method> = bound_method %.loc11_18.3, %DestroyT.binding.as_type.as.Destroy.impl.Op.specific_fn.1

0 commit comments

Comments
 (0)